Compare commits

...

5 Commits

Author SHA1 Message Date
Matt Hook
1bb253479a bump version to 2.14.1 (#7237)
Some checks failed
Test / test-client (push) Has been cancelled
2022-07-12 11:03:49 +12:00
Dakota Walsh
f0a13a2ad1 fix(migration): close the database before running backups EE-3627 (#7217)
* fix(migration): close the database before running backups

On certain filesystems, particuarly NTFS when a network mounted windows
file server is used to store portainer's database, you are unable to
copy the database while it is open. To fix this we simply close the
database and then re-open it after a backup.

* handle close and open errors

* dont return error on nil
2022-07-08 21:04:55 +12:00
Matt Hook
f9b28aa0a1 fix(compose): use docker-compose plugin directly [EE-3631] (#7201)
* use simplifed method of calling compose directly with new compose wrapper

* download compose binary to docker-compose

* update to newer wrapper that fixes -H issue

* update to released
2022-07-08 16:02:37 +12:00
LP B
d26e1b6983 fix(k8s/app-templates): display moustache variables fields when deploying from app template (#7185) 2022-07-08 14:15:16 +12:00
Dmitry Salakhov
7b00fdd208 fix(users): enable manual user addition [EE-3639] (#7196) 2022-07-06 15:47:51 +12:00
13 changed files with 84 additions and 31 deletions

View File

@@ -103,8 +103,26 @@ func (store *Store) backupWithOptions(options *BackupOptions) (string, error) {
store.createBackupFolders()
options = store.setupOptions(options)
dbPath := store.databasePath()
return options.BackupPath, store.copyDBFile(store.databasePath(), options.BackupPath)
if err := store.Close(); err != nil {
return options.BackupPath, fmt.Errorf(
"error closing datastore before creating backup: %v",
err,
)
}
if err := store.copyDBFile(dbPath, options.BackupPath); err != nil {
return options.BackupPath, err
}
if _, err := store.Open(); err != nil {
return options.BackupPath, fmt.Errorf(
"error opening datastore after creating backup: %v",
err,
)
}
return options.BackupPath, nil
}
// RestoreWithOptions previously saved backup for the current Edition with options

View File

@@ -910,7 +910,7 @@
],
"version": {
"DB_UPDATING": "false",
"DB_VERSION": "50",
"DB_VERSION": "51",
"INSTANCE_ID": "null"
}
}

View File

@@ -81,7 +81,7 @@ func (manager *ComposeStackManager) Down(ctx context.Context, stack *portainer.S
}
filePaths := stackutils.GetStackFilePaths(stack)
err = manager.deployer.Remove(ctx, stack.ProjectPath, url, stack.Name, filePaths)
err = manager.deployer.Remove(ctx, stack.ProjectPath, url, stack.Name, filePaths, "")
return errors.Wrap(err, "failed to remove a stack")
}

View File

@@ -32,7 +32,7 @@ require (
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c
github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6
github.com/pkg/errors v0.9.1
github.com/portainer/docker-compose-wrapper v0.0.0-20220531190153-c597b853e410
github.com/portainer/docker-compose-wrapper v0.0.0-20220708023447-a69a4ebaa021
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a
github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108
github.com/portainer/libhttp v0.0.0-20211208103139-07a5f798eb3f

View File

@@ -807,10 +807,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/portainer/docker-compose-wrapper v0.0.0-20220526210722-e1574867298e h1:gW1Ooaj7RZ9YkwHxesnNEyOB5nUD71FlZ7cdb5h63vw=
github.com/portainer/docker-compose-wrapper v0.0.0-20220526210722-e1574867298e/go.mod h1:WxDlJWZxCnicdLCPnLNEv7/gRhjeIVuCGmsv+iOPH3c=
github.com/portainer/docker-compose-wrapper v0.0.0-20220531190153-c597b853e410 h1:LjxLd8UGR8ae73ov/vLrt/0jedj/nh98XnONkr8DJj8=
github.com/portainer/docker-compose-wrapper v0.0.0-20220531190153-c597b853e410/go.mod h1:WxDlJWZxCnicdLCPnLNEv7/gRhjeIVuCGmsv+iOPH3c=
github.com/portainer/docker-compose-wrapper v0.0.0-20220708023447-a69a4ebaa021 h1:GFTn2e5AyIoBuK6hXbdVNkuV2m450DQnYmgQDZRU3x8=
github.com/portainer/docker-compose-wrapper v0.0.0-20220708023447-a69a4ebaa021/go.mod h1:WxDlJWZxCnicdLCPnLNEv7/gRhjeIVuCGmsv+iOPH3c=
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a h1:qY8TbocN75n5PDl16o0uVr5MevtM5IhdwSelXEd4nFM=
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a/go.mod h1:n54EEIq+MM0NNtqLeCby8ljL+l275VpolXO0ibHegLE=
github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108 h1:5e8KAnDa2G3cEHK7aV/ue8lOaoQwBZUzoALslwWkR04=

View File

@@ -80,7 +80,7 @@ type Handler struct {
}
// @title PortainerCE API
// @version 2.14.0
// @version 2.14.1
// @description.markdown api-description.md
// @termsOfService

View File

@@ -1385,9 +1385,9 @@ type (
const (
// APIVersion is the version number of the Portainer API
APIVersion = "2.14.0"
APIVersion = "2.14.1"
// DBVersion is the version number of the Portainer database
DBVersion = 50
DBVersion = 51
// ComposeSyntaxMaxVersion is a maximum supported version of the docker compose syntax
ComposeSyntaxMaxVersion = "3.9"
// AssetsServerURL represents the URL of the Portainer asset server

View File

@@ -93,7 +93,7 @@
></custom-template-selector>
<custom-templates-variables-field
ng-if="$ctrl.isTemplateVariablesEnabled && ctrl.state.template"
ng-if="ctrl.isTemplateVariablesEnabled && ctrl.state.template"
definitions="ctrl.state.template.Variables"
value="ctrl.formValues.Variables"
on-change="(ctrl.onChangeTemplateVariables)"

View File

@@ -5,6 +5,8 @@ import { AccessControlFormData } from '@/portainer/components/accessControlForm/
import { STACK_NAME_VALIDATION_REGEX } from '@/constants';
import { RepositoryMechanismTypes } from '@/kubernetes/models/deploy';
import { FeatureId } from 'Portainer/feature-flags/enums';
import { isBE } from '@/portainer/feature-flags/feature-flags.service';
import { renderTemplate } from '@/react/portainer/custom-templates/components/utils';
angular
.module('portainer.app')
@@ -31,6 +33,8 @@ angular
endpoint
) {
$scope.onChangeTemplateId = onChangeTemplateId;
$scope.onChangeTemplateVariables = onChangeTemplateVariables;
$scope.isTemplateVariablesEnabled = isBE;
$scope.buildAnalyticsProperties = buildAnalyticsProperties;
$scope.stackWebhookFeature = FeatureId.STACK_WEBHOOK;
$scope.STACK_NAME_VALIDATION_REGEX = STACK_NAME_VALIDATION_REGEX;
@@ -53,6 +57,7 @@ angular
RepositoryMechanism: RepositoryMechanismTypes.INTERVAL,
RepositoryFetchInterval: '5m',
RepositoryWebhookURL: WebhookHelper.returnStackWebhookUrl(uuidv4()),
Variables: {},
};
$scope.state = {
@@ -265,11 +270,12 @@ angular
});
};
$scope.onChangeFileContent = function onChangeFileContent(value) {
$scope.onChangeFileContent = onChangeFileContent;
function onChangeFileContent(value) {
$scope.formValues.StackFileContent = value;
$scope.state.editorYamlValidationError = StackHelper.validateYAML($scope.formValues.StackFileContent, $scope.containerNames);
$scope.state.isEditorDirty = true;
};
}
async function onFileLoadAsync(event) {
$scope.state.uploadYamlValidationError = StackHelper.validateYAML(event.target.result, $scope.containerNames);
@@ -292,18 +298,38 @@ angular
function onChangeTemplateId(templateId, template) {
return $async(async () => {
if (!template || ($scope.state.selectedTemplateId === templateId && $scope.state.selectedTemplate === template)) {
return;
}
try {
$scope.state.selectedTemplateId = templateId;
$scope.state.selectedTemplate = template;
const fileContent = await CustomTemplateService.customTemplateFile(templateId);
$scope.onChangeFileContent(fileContent);
$scope.state.templateContent = fileContent;
onChangeFileContent(fileContent);
if (template.Variables && template.Variables.length > 0) {
const variables = Object.fromEntries(template.Variables.map((variable) => [variable.name, '']));
onChangeTemplateVariables(variables);
}
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to retrieve Custom Template file');
Notifications.error('Failure', err, 'Unable to retrieve Custom Template file');
}
});
}
function onChangeTemplateVariables(value) {
onChangeFormValues({ Variables: value });
if (!$scope.isTemplateVariablesEnabled) {
return;
}
const rendered = renderTemplate($scope.state.templateContent, $scope.formValues.Variables, $scope.state.selectedTemplate.Variables);
onChangeFormValues({ StackFileContent: rendered });
}
async function initView() {
var endpointMode = $scope.applicationState.endpoint.mode;
$scope.state.StackType = 2;
@@ -328,8 +354,11 @@ angular
initView();
function onChangeFormValues(newValues) {
$scope.formValues = newValues;
function onChangeFormValues(values) {
$scope.formValues = {
...$scope.formValues,
...values,
};
}
}
);

View File

@@ -131,13 +131,21 @@
path-placeholder="docker-compose.yml"
></git-form>
<custom-template-selector
ng-show="state.Method === 'template'"
new-template-path="docker.templates.custom.new"
stack-type="state.StackType"
on-change="(onChangeTemplateId)"
value="state.selectedTemplateId"
></custom-template-selector>
<div ng-show="state.Method === 'template'">
<custom-template-selector
new-template-path="docker.templates.custom.new"
stack-type="state.StackType"
on-change="(onChangeTemplateId)"
value="state.selectedTemplateId"
></custom-template-selector>
<custom-templates-variables-field
ng-if="isTemplateVariablesEnabled && state.selectedTemplate"
definitions="state.selectedTemplate.Variables"
value="formValues.Variables"
on-change="(onChangeTemplateVariables)"
></custom-templates-variables-field>
</div>
<web-editor-form
ng-if="state.Method === 'editor' || (state.Method === 'template' && state.selectedTemplateId)"

View File

@@ -140,7 +140,7 @@
<button
type="button"
class="btn btn-primary btn-sm"
ng-disabled="state.actionInProgress || !state.validUsername || formValues.Username === '' || !formValues.Password || !formValues.ConfirmPassword || (AuthenticationMethod === 1 && form.$invalid) || (AuthenticationMethod === 1 && form.password.$viewValue !== formValues.ConfirmPassword)"
ng-disabled="state.actionInProgress || !state.validUsername || formValues.Username === '' || (AuthenticationMethod === 1 && (!formValues.Password || form.$invalid || formValues.Password !== formValues.ConfirmPassword))"
ng-click="addUser()"
button-spinner="state.actionInProgress"
data-cy="user-createUserButton"

View File

@@ -21,10 +21,10 @@ fi
if [[ "$PLATFORM" == "windows" ]]; then
wget -O "dist/docker-compose.plugin.exe" "https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-windows-${ARCH}.exe"
chmod +x "dist/docker-compose.plugin.exe"
wget -O "dist/docker-compose.exe" "https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-windows-${ARCH}.exe"
chmod +x "dist/docker-compose.exe"
else
wget -O "dist/docker-compose.plugin" "https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-${PLATFORM}-${ARCH}"
chmod +x "dist/docker-compose.plugin"
wget -O "dist/docker-compose" "https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-${PLATFORM}-${ARCH}"
chmod +x "dist/docker-compose"
fi

View File

@@ -2,7 +2,7 @@
"author": "Portainer.io",
"name": "portainer",
"homepage": "http://portainer.io",
"version": "2.14.0",
"version": "2.14.1",
"repository": {
"type": "git",
"url": "git@github.com:portainer/portainer.git"