Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb63a7ad7c | |||
| 76e4054215 | |||
| 0a3e13915c | |||
| dbd6e49e5f | |||
| abad58a370 | |||
| 4eb1c7b11f | |||
| 3afedce570 | |||
| a7b6db72a5 | |||
| 9c79d6dc7d | |||
| 11f612a501 | |||
| cb8d8fcfd6 | |||
| 22bb1e604d | |||
| 970b135261 | |||
| a69470ec08 | |||
| ea6f1c97f5 | |||
| 6d058987f3 | |||
| 6998f05855 | |||
| 94d01c58fc | |||
| d98eb77067 |
+1
-1
@@ -17,7 +17,7 @@ plugins:
|
||||
- import
|
||||
|
||||
parserOptions:
|
||||
ecmaVersion: 2018
|
||||
ecmaVersion: latest
|
||||
sourceType: module
|
||||
project: './tsconfig.json'
|
||||
ecmaFeatures:
|
||||
|
||||
@@ -615,7 +615,7 @@
|
||||
"RequiredPasswordLength": 12
|
||||
},
|
||||
"KubeconfigExpiry": "0",
|
||||
"KubectlShellImage": "portainer/kubectl-shell:2.33.3",
|
||||
"KubectlShellImage": "portainer/kubectl-shell:2.33.6",
|
||||
"LDAPSettings": {
|
||||
"AnonymousMode": true,
|
||||
"AutoCreateUsers": true,
|
||||
@@ -944,7 +944,7 @@
|
||||
}
|
||||
],
|
||||
"version": {
|
||||
"VERSION": "{\"SchemaVersion\":\"2.33.3\",\"MigratorCount\":0,\"Edition\":1,\"InstanceID\":\"463d5c47-0ea5-4aca-85b1-405ceefee254\"}"
|
||||
"VERSION": "{\"SchemaVersion\":\"2.33.6\",\"MigratorCount\":0,\"Edition\":1,\"InstanceID\":\"463d5c47-0ea5-4aca-85b1-405ceefee254\"}"
|
||||
},
|
||||
"webhooks": null
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func (handler *Handler) edgeStackStatusUpdate(w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
|
||||
if err := handler.requestBouncer.AuthorizedEdgeEndpointOperation(r, endpoint); err != nil {
|
||||
return httperror.Forbidden("Permission denied to access environment", fmt.Errorf("unauthorized edge endpoint operation: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.Forbidden("Permission denied to access environment", fmt.Errorf("unauthorized edge endpoint operation: %w. Environment ID: %d", err, payload.EndpointID))
|
||||
}
|
||||
|
||||
var stack *portainer.EdgeStack
|
||||
|
||||
@@ -42,17 +42,17 @@ func (handler *Handler) endpointEdgeJobsLogs(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
|
||||
if err := handler.requestBouncer.AuthorizedEdgeEndpointOperation(r, endpoint); err != nil {
|
||||
return httperror.Forbidden("Permission denied to access environment", fmt.Errorf("unauthorized edge endpoint operation: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.Forbidden("Permission denied to access environment", fmt.Errorf("unauthorized edge endpoint operation: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
edgeJobID, err := request.RetrieveNumericRouteVariableValue(r, "jobID")
|
||||
if err != nil {
|
||||
return httperror.BadRequest("Invalid edge job identifier route variable", fmt.Errorf("invalid Edge job route variable: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.BadRequest("Invalid edge job identifier route variable", fmt.Errorf("invalid Edge job route variable: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
var payload logsPayload
|
||||
if err := request.DecodeAndValidateJSONPayload(r, &payload); err != nil {
|
||||
return httperror.BadRequest("Invalid request payload", fmt.Errorf("invalid Edge job request payload: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.BadRequest("Invalid request payload", fmt.Errorf("invalid Edge job request payload: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
if err := handler.DataStore.UpdateTx(func(tx dataservices.DataStoreTx) error {
|
||||
@@ -60,11 +60,11 @@ func (handler *Handler) endpointEdgeJobsLogs(w http.ResponseWriter, r *http.Requ
|
||||
}); err != nil {
|
||||
var httpErr *httperror.HandlerError
|
||||
if errors.As(err, &httpErr) {
|
||||
httpErr.Err = fmt.Errorf("edge polling error: %w. Environment name: %s", httpErr.Err, endpoint.Name)
|
||||
httpErr.Err = fmt.Errorf("edge polling error: %w. Environment ID: %d", httpErr.Err, endpoint.ID)
|
||||
return httpErr
|
||||
}
|
||||
|
||||
return httperror.InternalServerError("Unexpected error", fmt.Errorf("edge polling error: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.InternalServerError("Unexpected error", fmt.Errorf("edge polling error: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
return response.JSON(w, nil)
|
||||
|
||||
@@ -40,18 +40,18 @@ func (handler *Handler) endpointEdgeStackInspect(w http.ResponseWriter, r *http.
|
||||
}
|
||||
|
||||
if err := handler.requestBouncer.AuthorizedEdgeEndpointOperation(r, endpoint); err != nil {
|
||||
return httperror.Forbidden("Permission denied to access environment", fmt.Errorf("unauthorized edge endpoint operation: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.Forbidden("Permission denied to access environment", fmt.Errorf("unauthorized edge endpoint operation: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
edgeStackID, err := request.RetrieveNumericRouteVariableValue(r, "stackId")
|
||||
if err != nil {
|
||||
return httperror.BadRequest("Invalid edge stack identifier route variable", fmt.Errorf("invalid Edge stack route variable: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.BadRequest("Invalid edge stack identifier route variable", fmt.Errorf("invalid Edge stack route variable: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
s, err, _ := edgeStackSingleFlightGroup.Do(strconv.Itoa(edgeStackID), func() (any, error) {
|
||||
edgeStack, err := handler.DataStore.EdgeStack().EdgeStack(portainer.EdgeStackID(edgeStackID))
|
||||
if handler.DataStore.IsErrObjectNotFound(err) {
|
||||
return nil, httperror.NotFound("Unable to find an edge stack with the specified identifier inside the database", fmt.Errorf("unable to find the Edge stack from database: %w. Environment name: %s", err, endpoint.Name))
|
||||
return nil, httperror.NotFound("Unable to find an edge stack with the specified identifier inside the database", fmt.Errorf("unable to find the Edge stack from database: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
return edgeStack, err
|
||||
@@ -62,7 +62,7 @@ func (handler *Handler) endpointEdgeStackInspect(w http.ResponseWriter, r *http.
|
||||
return httpErr
|
||||
}
|
||||
|
||||
return httperror.InternalServerError("Unable to find an edge stack with the specified identifier inside the database", fmt.Errorf("failed to find Edge stack from the database: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.InternalServerError("Unable to find an edge stack with the specified identifier inside the database", fmt.Errorf("failed to find Edge stack from the database: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
// WARNING: this variable must not be mutated
|
||||
@@ -71,7 +71,7 @@ func (handler *Handler) endpointEdgeStackInspect(w http.ResponseWriter, r *http.
|
||||
fileName := edgeStack.EntryPoint
|
||||
if endpointutils.IsDockerEndpoint(endpoint) {
|
||||
if fileName == "" {
|
||||
return httperror.BadRequest("Docker is not supported by this stack", fmt.Errorf("no filename is provided for the Docker endpoint. Environment name: %s", endpoint.Name))
|
||||
return httperror.BadRequest("Docker is not supported by this stack", fmt.Errorf("no filename is provided for the Docker endpoint. Environment ID: %d", endpoint.ID))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,18 +84,18 @@ func (handler *Handler) endpointEdgeStackInspect(w http.ResponseWriter, r *http.
|
||||
fileName = edgeStack.ManifestPath
|
||||
|
||||
if fileName == "" {
|
||||
return httperror.BadRequest("Kubernetes is not supported by this stack", fmt.Errorf("no filename is provided for the Kubernetes endpoint. Environment name: %s", endpoint.Name))
|
||||
return httperror.BadRequest("Kubernetes is not supported by this stack", fmt.Errorf("no filename is provided for the Kubernetes endpoint. Environment ID: %d", endpoint.ID))
|
||||
}
|
||||
}
|
||||
|
||||
dirEntries, err := filesystem.LoadDir(edgeStack.ProjectPath)
|
||||
if err != nil {
|
||||
return httperror.InternalServerError("Unable to load repository", fmt.Errorf("failed to load project directory: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.InternalServerError("Unable to load repository", fmt.Errorf("failed to load project directory: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
fileContent, err := filesystem.FilterDirForCompatibility(dirEntries, fileName, endpoint.Agent.Version)
|
||||
if err != nil {
|
||||
return httperror.InternalServerError("File not found", fmt.Errorf("unable to find file: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.InternalServerError("File not found", fmt.Errorf("unable to find file: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
dirEntries = filesystem.FilterDirForEntryFile(dirEntries, fileName)
|
||||
|
||||
@@ -97,13 +97,13 @@ func (handler *Handler) endpointEdgeStatusInspect(w http.ResponseWriter, r *http
|
||||
firstConn := endpoint.LastCheckInDate == 0
|
||||
|
||||
if err := handler.requestBouncer.AuthorizedEdgeEndpointOperation(r, endpoint); err != nil {
|
||||
return httperror.Forbidden("Permission denied to access environment. The device has not been trusted yet", fmt.Errorf("unauthorized Edge endpoint operation: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.Forbidden("Permission denied to access environment. The device has not been trusted yet", fmt.Errorf("unauthorized Edge endpoint operation: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
handler.DataStore.Endpoint().UpdateHeartbeat(endpoint.ID)
|
||||
|
||||
if err := handler.requestBouncer.TrustedEdgeEnvironmentAccess(handler.DataStore, endpoint); err != nil {
|
||||
return httperror.Forbidden("Permission denied to access environment. The device has not been trusted yet", fmt.Errorf("untrusted Edge environment access: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.Forbidden("Permission denied to access environment. The device has not been trusted yet", fmt.Errorf("untrusted Edge environment access: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
var statusResponse *endpointEdgeStatusInspectResponse
|
||||
@@ -113,11 +113,11 @@ func (handler *Handler) endpointEdgeStatusInspect(w http.ResponseWriter, r *http
|
||||
}); err != nil {
|
||||
var httpErr *httperror.HandlerError
|
||||
if errors.As(err, &httpErr) {
|
||||
httpErr.Err = fmt.Errorf("edge polling error: %w. Environment name: %s", httpErr.Err, endpoint.Name)
|
||||
httpErr.Err = fmt.Errorf("edge polling error: %w. Environment ID: %d", httpErr.Err, endpoint.ID)
|
||||
return httpErr
|
||||
}
|
||||
|
||||
return httperror.InternalServerError("Unexpected error", fmt.Errorf("edge polling error: %w. Environment name: %s", err, endpoint.Name))
|
||||
return httperror.InternalServerError("Unexpected error", fmt.Errorf("edge polling error: %w. Environment ID: %d", err, endpoint.ID))
|
||||
}
|
||||
|
||||
return cacheResponse(w, endpoint.ID, *statusResponse)
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
// @produce json
|
||||
// @param id path int true "Environment(Endpoint) identifier"
|
||||
// @param excludeSnapshot query bool false "if true, the snapshot data won't be retrieved"
|
||||
// @param excludeSnapshotRaw query bool false "if true, the SnapshotRaw field won't be retrieved"
|
||||
// @success 200 {object} portainer.Endpoint "Success"
|
||||
// @failure 400 "Invalid request"
|
||||
// @failure 404 "Environment(Endpoint) not found"
|
||||
@@ -53,10 +52,9 @@ func (handler *Handler) endpointInspect(w http.ResponseWriter, r *http.Request)
|
||||
endpoint.ComposeSyntaxMaxVersion = handler.ComposeStackManager.ComposeSyntaxMaxVersion()
|
||||
|
||||
excludeSnapshot, _ := request.RetrieveBooleanQueryParameter(r, "excludeSnapshot", true)
|
||||
excludeRaw, _ := request.RetrieveBooleanQueryParameter(r, "excludeSnapshotRaw", true)
|
||||
|
||||
if !excludeSnapshot {
|
||||
if err := handler.SnapshotService.FillSnapshotData(endpoint, !excludeRaw); err != nil {
|
||||
if err := handler.SnapshotService.FillSnapshotData(endpoint, false); err != nil {
|
||||
return httperror.InternalServerError("Unable to add snapshot data", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ const (
|
||||
// @param edgeDeviceUntrusted query bool false "if true, show only untrusted edge agents, if false show only trusted edge agents (relevant only for edge agents)"
|
||||
// @param edgeCheckInPassedSeconds query number false "if bigger then zero, show only edge agents that checked-in in the last provided seconds (relevant only for edge agents)"
|
||||
// @param excludeSnapshots query bool false "if true, the snapshot data won't be retrieved"
|
||||
// @param excludeSnapshotRaw query bool false "if true, the SnapshotRaw field won't be retrieved"
|
||||
// @param name query string false "will return only environments(endpoints) with this name"
|
||||
// @param edgeStackId query portainer.EdgeStackID false "will return the environements of the specified edge stack"
|
||||
// @param edgeStackStatus query string false "only applied when edgeStackId exists. Filter the returned environments based on their deployment status in the stack (not the environment status!)" Enum("Pending", "Ok", "Error", "Acknowledged", "Remove", "RemoteUpdateSuccess", "ImagesPulled")
|
||||
@@ -63,7 +62,6 @@ func (handler *Handler) endpointList(w http.ResponseWriter, r *http.Request) *ht
|
||||
limit, _ := request.RetrieveNumericQueryParameter(r, "limit", true)
|
||||
sortField, _ := request.RetrieveQueryParameter(r, "sort", true)
|
||||
sortOrder, _ := request.RetrieveQueryParameter(r, "order", true)
|
||||
excludeRaw, _ := request.RetrieveBooleanQueryParameter(r, "excludeSnapshotRaw", true)
|
||||
|
||||
endpointGroups, err := handler.DataStore.EndpointGroup().ReadAll()
|
||||
if err != nil {
|
||||
@@ -118,7 +116,7 @@ func (handler *Handler) endpointList(w http.ResponseWriter, r *http.Request) *ht
|
||||
endpointutils.UpdateEdgeEndpointHeartbeat(&paginatedEndpoints[idx], settings)
|
||||
|
||||
if !query.excludeSnapshots {
|
||||
if err := handler.SnapshotService.FillSnapshotData(&paginatedEndpoints[idx], !excludeRaw); err != nil {
|
||||
if err := handler.SnapshotService.FillSnapshotData(&paginatedEndpoints[idx], false); err != nil {
|
||||
return httperror.InternalServerError("Unable to add snapshot data", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ type Handler struct {
|
||||
}
|
||||
|
||||
// @title PortainerCE API
|
||||
// @version 2.33.3
|
||||
// @version 2.33.6
|
||||
// @description.markdown api-description.md
|
||||
// @termsOfService
|
||||
|
||||
|
||||
@@ -161,7 +161,13 @@ func (handler *Handler) startStack(
|
||||
return handler.StackDeployer.StartRemoteComposeStack(stack, endpoint, filteredRegistries)
|
||||
}
|
||||
|
||||
return handler.ComposeStackManager.Up(context.TODO(), stack, endpoint, portainer.ComposeUpOptions{})
|
||||
options := portainer.ComposeUpOptions{
|
||||
ComposeOptions: portainer.ComposeOptions{
|
||||
Registries: filteredRegistries,
|
||||
},
|
||||
}
|
||||
|
||||
return handler.ComposeStackManager.Up(context.TODO(), stack, endpoint, options)
|
||||
case portainer.DockerSwarmStack:
|
||||
stack.Name = handler.SwarmStackManager.NormalizeStackName(stack.Name)
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ var prefixProxyFuncMap = map[string]func(*Transport, *http.Request, string) (*ht
|
||||
// ProxyDockerRequest intercepts a Docker API request and apply logic based
|
||||
// on the requested operation.
|
||||
func (transport *Transport) ProxyDockerRequest(request *http.Request) (*http.Response, error) {
|
||||
// from : /v1.41/containers/{id}/json
|
||||
// from : /v1.44/containers/{id}/json
|
||||
// or : /containers/{id}/json
|
||||
// to : /containers/{id}/json
|
||||
unversionedPath := apiVersionRe.ReplaceAllString(request.URL.Path, "")
|
||||
|
||||
+1
-1
@@ -1782,7 +1782,7 @@ type (
|
||||
|
||||
const (
|
||||
// APIVersion is the version number of the Portainer API
|
||||
APIVersion = "2.33.3"
|
||||
APIVersion = "2.33.6"
|
||||
// Support annotation for the API version ("STS" for Short-Term Support or "LTS" for Long-Term Support)
|
||||
APIVersionSupport = "LTS"
|
||||
// Edition is what this edition of Portainer is called
|
||||
|
||||
@@ -55,12 +55,11 @@ func (d *stackDeployer) DeployRemoteComposeStack(
|
||||
d.lock.Lock()
|
||||
defer d.lock.Unlock()
|
||||
|
||||
d.swarmStackManager.Login(registries, endpoint)
|
||||
defer d.swarmStackManager.Logout(endpoint)
|
||||
options := portainer.ComposeOptions{Registries: registries}
|
||||
|
||||
// --force-recreate doesn't pull updated images
|
||||
if forcePullImage {
|
||||
if err := d.composeStackManager.Pull(context.TODO(), stack, endpoint, portainer.ComposeOptions{}); err != nil {
|
||||
if err := d.composeStackManager.Pull(context.TODO(), stack, endpoint, options); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,9 +117,7 @@ div.input-mask {
|
||||
.widget .widget-body .error {
|
||||
color: #ff0000;
|
||||
}
|
||||
.widget .widget-body button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.widget .widget-body div.alert {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { NodeStatus, TaskState } from 'docker-types/generated/1.41';
|
||||
import { NodeStatus, TaskState } from 'docker-types/generated/1.44';
|
||||
import _ from 'lodash';
|
||||
|
||||
export function trimVersionTag(fullName: string) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Config } from 'docker-types/generated/1.41';
|
||||
import { Config } from 'docker-types/generated/1.44';
|
||||
|
||||
import { IResource } from '@/react/docker/components/datatable/createOwnershipColumn';
|
||||
import { PortainerResponse } from '@/react/docker/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ImageSummary } from 'docker-types/generated/1.41';
|
||||
import { ImageSummary } from 'docker-types/generated/1.44';
|
||||
|
||||
import { PortainerResponse } from '@/react/docker/types';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ImageInspect } from 'docker-types/generated/1.41';
|
||||
import { ImageInspect } from 'docker-types/generated/1.44';
|
||||
|
||||
type ImageInspectConfig = NonNullable<ImageInspect['Config']>;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IPAM, Network, NetworkContainer } from 'docker-types/generated/1.41';
|
||||
import { IPAM, Network, NetworkContainer } from 'docker-types/generated/1.44';
|
||||
|
||||
import { ResourceControlViewModel } from '@/react/portainer/access-control/models/ResourceControlViewModel';
|
||||
import { IResource } from '@/react/docker/components/datatable/createOwnershipColumn';
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
ObjectVersion,
|
||||
Platform,
|
||||
ResourceObject,
|
||||
} from 'docker-types/generated/1.41';
|
||||
} from 'docker-types/generated/1.44';
|
||||
|
||||
export class NodeViewModel {
|
||||
Model: Node;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Secret } from 'docker-types/generated/1.41';
|
||||
import { Secret } from 'docker-types/generated/1.44';
|
||||
|
||||
import { ResourceControlViewModel } from '@/react/portainer/access-control/models/ResourceControlViewModel';
|
||||
import { PortainerResponse } from '@/react/docker/types';
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
Service,
|
||||
ServiceSpec,
|
||||
TaskSpec,
|
||||
} from 'docker-types/generated/1.41';
|
||||
} from 'docker-types/generated/1.44';
|
||||
|
||||
import { ResourceControlViewModel } from '@/react/portainer/access-control/models/ResourceControlViewModel';
|
||||
import { PortainerResponse } from '@/react/docker/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Task } from 'docker-types/generated/1.41';
|
||||
import { Task } from 'docker-types/generated/1.44';
|
||||
|
||||
import { DeepPick } from '@/types/deepPick';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Volume } from 'docker-types/generated/1.41';
|
||||
import { Volume } from 'docker-types/generated/1.44';
|
||||
|
||||
import { ResourceControlViewModel } from '@/react/portainer/access-control/models/ResourceControlViewModel';
|
||||
import { IResource } from '@/react/docker/components/datatable/createOwnershipColumn';
|
||||
|
||||
@@ -720,7 +720,7 @@ angular.module('portainer.docker').controller('ServiceController', [
|
||||
|
||||
$scope.onResetPorts = function (all = false) {
|
||||
$scope.$evalAsync(() => {
|
||||
$scope.formValues.ports = portsMappingUtils.toViewModel($scope.service.Model.Spec.EndpointSpec.Ports);
|
||||
$scope.formValues.ports = portsMappingUtils.toViewModel($scope.service.Model.Spec.EndpointSpec?.Ports);
|
||||
|
||||
$scope.cancelChanges($scope.service, all ? undefined : ['Ports']);
|
||||
});
|
||||
@@ -744,7 +744,7 @@ angular.module('portainer.docker').controller('ServiceController', [
|
||||
$scope.lastVersion = service.Version;
|
||||
}
|
||||
|
||||
$scope.formValues.ports = portsMappingUtils.toViewModel(service.Model.Spec.EndpointSpec.Ports);
|
||||
$scope.formValues.ports = portsMappingUtils.toViewModel(service.Model.Spec.EndpointSpec?.Ports);
|
||||
|
||||
transformResources(service);
|
||||
translateServiceArrays(service);
|
||||
|
||||
@@ -4,8 +4,4 @@ export const MaxDockerAPIVersionKey = 'maxDockerAPIVersion' as const;
|
||||
export type DockerAPIVersionType = number;
|
||||
|
||||
// this is the version we are using with the generated API types
|
||||
export const MAX_DOCKER_API_VERSION: DockerAPIVersionType = 1.41;
|
||||
|
||||
// https://docs.docker.com/engine/api/#api-version-matrix
|
||||
// Docker 26 = API 1.45
|
||||
export const LATEST_DOCKER_API_VERSION: DockerAPIVersionType = 1.45;
|
||||
export const MAX_DOCKER_API_VERSION: DockerAPIVersionType = 1.44;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SystemVersion } from 'docker-types/generated/1.41';
|
||||
import { SystemVersion } from 'docker-types/generated/1.44';
|
||||
import Axios, { InternalAxiosRequestConfig } from 'axios';
|
||||
import { setupCache, buildMemoryStorage } from 'axios-cache-interceptor';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Config } from 'docker-types/generated/1.41';
|
||||
import { Config } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Config } from 'docker-types/generated/1.41';
|
||||
import { Config } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ConfigSpec } from 'docker-types/generated/1.41';
|
||||
import { ConfigSpec } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PortMap } from 'docker-types/generated/1.41';
|
||||
import { PortMap } from 'docker-types/generated/1.44';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { PortMapping, Protocol, Values } from './PortsMappingField';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PortMap } from 'docker-types/generated/1.41';
|
||||
import { PortMap } from 'docker-types/generated/1.44';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { Protocol, Values } from './PortsMappingField';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { mixed } from 'yup';
|
||||
import { ContainerConfig } from 'docker-types/generated/1.41';
|
||||
import { ContainerConfig } from 'docker-types/generated/1.44';
|
||||
|
||||
import { AutomationTestingProps } from '@/types';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HostConfig } from 'docker-types/generated/1.41';
|
||||
import { HostConfig } from 'docker-types/generated/1.44';
|
||||
|
||||
import { commandArrayToString } from '@/docker/helpers/containers';
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
import { CreateContainerRequest } from '../types';
|
||||
|
||||
import { toRequest } from './toRequest';
|
||||
import { Values } from './types';
|
||||
|
||||
describe('toRequest', () => {
|
||||
const mockOldConfig: CreateContainerRequest = {
|
||||
Hostname: 'old-hostname',
|
||||
Domainname: 'old-domain',
|
||||
MacAddress: '02:42:ac:11:00:99',
|
||||
HostConfig: {
|
||||
NetworkMode: 'bridge',
|
||||
Dns: ['1.1.1.1'],
|
||||
ExtraHosts: [],
|
||||
},
|
||||
NetworkingConfig: {
|
||||
EndpointsConfig: {
|
||||
bridge: {
|
||||
Aliases: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mockValues: Values = {
|
||||
networkMode: 'bridge',
|
||||
hostname: 'new-hostname',
|
||||
domain: 'new-domain',
|
||||
macAddress: '02:42:ac:11:00:88',
|
||||
ipv4Address: '172.17.0.5',
|
||||
ipv6Address: 'fe80::42:acff:fe11:5',
|
||||
primaryDns: '8.8.8.8',
|
||||
secondaryDns: '8.8.4.4',
|
||||
hostsFileEntries: ['host1:127.0.0.1'],
|
||||
container: '',
|
||||
};
|
||||
|
||||
it('should use MAC address from values, not from oldConfig', () => {
|
||||
const oldMacAddress = '02:42:ac:11:00:99';
|
||||
const macAddress = '02:42:ac:11:00:88';
|
||||
const result = toRequest(
|
||||
{ ...mockOldConfig, MacAddress: oldMacAddress },
|
||||
{ ...mockValues, macAddress },
|
||||
'container-123'
|
||||
);
|
||||
|
||||
expect(result.MacAddress).toBe(macAddress);
|
||||
expect(result.MacAddress).not.toBe(oldMacAddress);
|
||||
});
|
||||
|
||||
it('should allow empty MAC address when duplicating containers', () => {
|
||||
const valuesWithEmptyMac: Values = {
|
||||
...mockValues,
|
||||
macAddress: '', // Empty MAC from toViewModel
|
||||
};
|
||||
|
||||
const result = toRequest(
|
||||
mockOldConfig,
|
||||
valuesWithEmptyMac,
|
||||
'container-123'
|
||||
);
|
||||
|
||||
expect(result.MacAddress).toBe('');
|
||||
expect(result.MacAddress).not.toBe(mockOldConfig.MacAddress);
|
||||
});
|
||||
|
||||
it('should set other network properties from values', () => {
|
||||
const result = toRequest(mockOldConfig, mockValues, 'container-123');
|
||||
|
||||
expect(result.Hostname).toBe('new-hostname');
|
||||
expect(result.Domainname).toBe('new-domain');
|
||||
expect(result.HostConfig.NetworkMode).toBe('bridge');
|
||||
expect(result.HostConfig.Dns).toEqual(['8.8.8.8', '8.8.4.4']);
|
||||
expect(result.HostConfig.ExtraHosts).toEqual(['host1:127.0.0.1']);
|
||||
expect(result.NetworkingConfig.EndpointsConfig?.bridge.IPAMConfig).toEqual({
|
||||
IPv4Address: '172.17.0.5',
|
||||
IPv6Address: 'fe80::42:acff:fe11:5',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,11 @@ import { DockerNetwork } from '@/react/docker/networks/types';
|
||||
import { ContainerListViewModel } from '../../types';
|
||||
import { ContainerDetailsJSON } from '../../queries/useContainer';
|
||||
|
||||
import { getDefaultViewModel, getNetworkMode } from './toViewModel';
|
||||
import {
|
||||
getDefaultViewModel,
|
||||
getNetworkMode,
|
||||
toViewModel,
|
||||
} from './toViewModel';
|
||||
|
||||
describe('getDefaultViewModel', () => {
|
||||
it('should return the correct default view model for Windows', () => {
|
||||
@@ -145,3 +149,86 @@ describe('getNetworkMode', () => {
|
||||
expect(getNetworkMode(config, mockNetworks)).toEqual(['bridge']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toViewModel', () => {
|
||||
const mockNetworks: Array<DockerNetwork> = [
|
||||
{
|
||||
Name: 'bridge',
|
||||
Id: 'bridge-id',
|
||||
Driver: 'bridge',
|
||||
Scope: 'local',
|
||||
Attachable: false,
|
||||
Internal: false,
|
||||
IPAM: { Config: [], Driver: '', Options: {} },
|
||||
Options: {},
|
||||
Containers: {},
|
||||
},
|
||||
];
|
||||
|
||||
it('should copy network settings while clearing mac address', () => {
|
||||
const config: ContainerDetailsJSON = {
|
||||
Config: {
|
||||
Hostname: 'test-host',
|
||||
Domainname: 'test-domain',
|
||||
},
|
||||
HostConfig: {
|
||||
NetworkMode: 'bridge',
|
||||
Dns: ['8.8.8.8', '8.8.4.4'],
|
||||
ExtraHosts: ['host1:127.0.0.1'],
|
||||
},
|
||||
NetworkSettings: {
|
||||
Networks: {
|
||||
bridge: {
|
||||
MacAddress: '02:42:ac:11:00:02',
|
||||
IPAMConfig: {
|
||||
IPv4Address: '172.17.0.2',
|
||||
IPv6Address: 'fe80::42:acff:fe11:2',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = toViewModel(config, mockNetworks);
|
||||
|
||||
expect(result.macAddress).toBe('');
|
||||
expect(result.hostname).toBe('test-host');
|
||||
expect(result.domain).toBe('test-domain');
|
||||
expect(result.ipv4Address).toBe('172.17.0.2');
|
||||
expect(result.ipv6Address).toBe('fe80::42:acff:fe11:2');
|
||||
});
|
||||
|
||||
it('should return empty MAC address for new containers', () => {
|
||||
const config: ContainerDetailsJSON = {
|
||||
Config: {},
|
||||
HostConfig: { NetworkMode: 'bridge' },
|
||||
};
|
||||
|
||||
const result = toViewModel(config, mockNetworks);
|
||||
|
||||
expect(result.macAddress).toBe('');
|
||||
});
|
||||
|
||||
it('should not duplicate MAC address when duplicating containers', () => {
|
||||
const config: ContainerDetailsJSON = {
|
||||
Config: {
|
||||
Hostname: 'original-container',
|
||||
},
|
||||
HostConfig: {
|
||||
NetworkMode: 'bridge',
|
||||
},
|
||||
NetworkSettings: {
|
||||
Networks: {
|
||||
bridge: {
|
||||
MacAddress: '02:42:ac:11:00:99',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = toViewModel(config, mockNetworks);
|
||||
|
||||
expect(result.macAddress).toBe('');
|
||||
expect(result.hostname).toBe('original-container');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,13 +53,11 @@ export function toViewModel(
|
||||
ipv6Address = networkSettings.IPAMConfig.IPv6Address || '';
|
||||
}
|
||||
|
||||
const macAddress = networkSettings?.MacAddress || '';
|
||||
|
||||
return {
|
||||
networkMode,
|
||||
hostname: config.Config?.Hostname || '',
|
||||
domain: config.Config?.Domainname || '',
|
||||
macAddress,
|
||||
macAddress: '', // mac address is cleared between edit/duplicate
|
||||
ipv4Address,
|
||||
ipv6Address,
|
||||
primaryDns,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FormikErrors } from 'formik';
|
||||
import { array, object, SchemaOf, string } from 'yup';
|
||||
import { DeviceMapping } from 'docker-types/generated/1.41';
|
||||
import { DeviceMapping } from 'docker-types/generated/1.44';
|
||||
|
||||
import { FormError } from '@@/form-components/FormError';
|
||||
import { InputList, ItemProps } from '@@/form-components/InputList';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DeviceRequest } from 'docker-types/generated/1.41';
|
||||
import { DeviceRequest } from 'docker-types/generated/1.44';
|
||||
|
||||
import { Values } from './types';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DeviceRequest } from 'docker-types/generated/1.41';
|
||||
import { DeviceRequest } from 'docker-types/generated/1.44';
|
||||
|
||||
import { Values } from './types';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
ContainerConfig,
|
||||
HostConfig,
|
||||
NetworkingConfig,
|
||||
} from 'docker-types/generated/1.41';
|
||||
} from 'docker-types/generated/1.44';
|
||||
|
||||
export interface CreateContainerRequest extends ContainerConfig {
|
||||
HostConfig: HostConfig;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Network } from 'lucide-react';
|
||||
import { EndpointSettings, NetworkSettings } from 'docker-types/generated/1.41';
|
||||
import { EndpointSettings, NetworkSettings } from 'docker-types/generated/1.44';
|
||||
|
||||
import { createPersistedStore } from '@@/datatables/types';
|
||||
import { useTableState } from '@@/datatables/useTableState';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TableMeta } from '@tanstack/react-table';
|
||||
import { EndpointSettings } from 'docker-types/generated/1.41';
|
||||
import { EndpointSettings } from 'docker-types/generated/1.44';
|
||||
|
||||
export type TableNetwork = EndpointSettings & { id: string; name: string };
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
HostConfig,
|
||||
MountPoint,
|
||||
NetworkSettings,
|
||||
} from 'docker-types/generated/1.41';
|
||||
} from 'docker-types/generated/1.44';
|
||||
|
||||
import { PortainerResponse } from '@/react/docker/types';
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Resources, RestartPolicy } from 'docker-types/generated/1.41';
|
||||
import { Resources, RestartPolicy } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ContainerSummary } from 'docker-types/generated/1.41';
|
||||
import { ContainerSummary } from 'docker-types/generated/1.44';
|
||||
|
||||
import { PortainerResponse } from '@/react/docker/types';
|
||||
import { WithRequiredProperties } from '@/types';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createColumnHelper } from '@tanstack/react-table';
|
||||
import { Clock } from 'lucide-react';
|
||||
import { EventMessage } from 'docker-types/generated/1.41';
|
||||
import { EventMessage } from 'docker-types/generated/1.44';
|
||||
|
||||
import { isoDateFromTimestamp } from '@/portainer/filters/filters';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { EventMessage } from 'docker-types/generated/1.41';
|
||||
import { EventMessage } from 'docker-types/generated/1.44';
|
||||
|
||||
type EventType = NonNullable<EventMessage['Type']>;
|
||||
type Action = string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IPAMConfig } from 'docker-types/generated/1.41';
|
||||
import { IPAMConfig } from 'docker-types/generated/1.44';
|
||||
|
||||
import { NetworkViewModel } from '@/docker/models/network';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { EndpointSettings } from 'docker-types/generated/1.41';
|
||||
import { EndpointSettings } from 'docker-types/generated/1.44';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Network } from 'docker-types/generated/1.41';
|
||||
import { Network } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ImageInspect } from 'docker-types/generated/1.41';
|
||||
import { ImageInspect } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { ImageSummary } from 'docker-types/generated/1.41';
|
||||
import { ImageSummary } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Node } from 'docker-types/generated/1.41';
|
||||
import { Node } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Node } from 'docker-types/generated/1.41';
|
||||
import { Node } from 'docker-types/generated/1.44';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Node, NodeSpec } from 'docker-types/generated/1.41';
|
||||
import { Node, NodeSpec } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SecretSpec } from 'docker-types/generated/1.41';
|
||||
import { SecretSpec } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Secret } from 'docker-types/generated/1.41';
|
||||
import { Secret } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Secret } from 'docker-types/generated/1.41';
|
||||
import { Secret } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Task } from 'docker-types/generated/1.41';
|
||||
import { Task } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { EventMessage } from 'docker-types/generated/1.41';
|
||||
import { EventMessage } from 'docker-types/generated/1.44';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import axios, {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { SystemInfo } from 'docker-types/generated/1.41';
|
||||
import { SystemInfo } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
Plugin,
|
||||
PluginInterfaceType,
|
||||
PluginsInfo,
|
||||
} from 'docker-types/generated/1.41';
|
||||
} from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
@@ -87,7 +87,7 @@ export function aggregateData(
|
||||
(plugin) =>
|
||||
plugin.Enabled &&
|
||||
// docker has an error in their types, so we need to cast to unknown first
|
||||
// see https://docs.docker.com/engine/api/v1.41/#tag/Plugin/operation/PluginList
|
||||
// see https://docs.docker.com/engine/api/v1.44/#tag/Plugin/operation/PluginList
|
||||
plugin.Config.Interface.Types.includes(
|
||||
pluginTypeToVersionMap[pluginType] as unknown as PluginInterfaceType
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Swarm } from 'docker-types/generated/1.41';
|
||||
import { Swarm } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { SystemVersion } from 'docker-types/generated/1.41';
|
||||
import { SystemVersion } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { EndpointPortConfig } from 'docker-types/generated/1.41';
|
||||
import { EndpointPortConfig } from 'docker-types/generated/1.44';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { Values } from './PortsMappingField';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { EndpointPortConfig } from 'docker-types/generated/1.41';
|
||||
import { EndpointPortConfig } from 'docker-types/generated/1.44';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { PortBinding, Protocol, Value, isProtocol, isRange } from './types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Node } from 'docker-types/generated/1.41';
|
||||
import { Node } from 'docker-types/generated/1.44';
|
||||
import { CellContext } from '@tanstack/react-table';
|
||||
|
||||
import { useNodes } from '@/react/docker/proxy/queries/nodes/useNodes';
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { Node } from 'docker-types/generated/1.41';
|
||||
import { Node } from 'docker-types/generated/1.44';
|
||||
|
||||
import { ServiceViewModel } from '@/docker/models/service';
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { CellContext } from '@tanstack/react-table';
|
||||
import { Node } from 'docker-types/generated/1.41';
|
||||
import { Node } from 'docker-types/generated/1.44';
|
||||
|
||||
import { ServiceViewModel } from '@/docker/models/service';
|
||||
import { useNodes } from '@/react/docker/proxy/queries/nodes/useNodes';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Service } from 'docker-types/generated/1.41';
|
||||
import { Service } from 'docker-types/generated/1.44';
|
||||
|
||||
import { ServiceUpdateConfig } from '../types';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Service } from 'docker-types/generated/1.41';
|
||||
import { Service } from 'docker-types/generated/1.44';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Service } from 'docker-types/generated/1.41';
|
||||
import { Service } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { withGlobalError } from '@/react-tools/react-query';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Service } from 'docker-types/generated/1.41';
|
||||
import { Service } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { withGlobalError } from '@/react-tools/react-query';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ServiceUpdateResponse } from 'docker-types/generated/1.41';
|
||||
import { ServiceUpdateResponse } from 'docker-types/generated/1.44';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ServiceSpec, TaskSpec } from 'docker-types/generated/1.41';
|
||||
import { ServiceSpec, TaskSpec } from 'docker-types/generated/1.44';
|
||||
|
||||
export type ServiceId = string;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Task } from 'docker-types/generated/1.41';
|
||||
import { Task } from 'docker-types/generated/1.44';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Task } from 'docker-types/generated/1.41';
|
||||
import { Task } from 'docker-types/generated/1.44';
|
||||
|
||||
export type TaskId = NonNullable<Task['ID']>;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Volume, VolumeCreateOptions } from 'docker-types/generated/1.41';
|
||||
import { Volume, VolumeCreateOptions } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Volume } from 'docker-types/generated/1.41';
|
||||
import { Volume } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Volume } from 'docker-types/generated/1.41';
|
||||
import { Volume } from 'docker-types/generated/1.44';
|
||||
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Volume } from 'docker-types/generated/1.41';
|
||||
import { Volume } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Volume } from 'docker-types/generated/1.41';
|
||||
import { Volume } from 'docker-types/generated/1.44';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { buildDockerProxyUrl } from '@/react/docker/proxy/queries/buildDockerProxyUrl';
|
||||
|
||||
@@ -36,6 +36,7 @@ export function PrivateRegistryFieldset({
|
||||
}: Props) {
|
||||
const [checked, setChecked] = useState(isActive || false);
|
||||
const [selected, setSelected] = useState(value);
|
||||
const [isInitialMount, setIsInitialMount] = useState(true);
|
||||
|
||||
const tooltipMessage =
|
||||
'This allows you to provide credentials when using a private registry that requires authentication';
|
||||
@@ -47,6 +48,13 @@ export function PrivateRegistryFieldset({
|
||||
}, [isActive]);
|
||||
|
||||
useEffect(() => {
|
||||
// Skip onChange call on initial mount when checkbox is already checked
|
||||
// to preserve the saved registry value
|
||||
if (isInitialMount) {
|
||||
setIsInitialMount(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (checked) {
|
||||
onChange();
|
||||
} else {
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.sort-by-element {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RestartPolicy } from 'docker-types/generated/1.41';
|
||||
import { RestartPolicy } from 'docker-types/generated/1.44';
|
||||
|
||||
import { BasicTableSettings } from '@@/datatables/types';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import _ from 'lodash';
|
||||
import { RestartPolicy } from 'docker-types/generated/1.41';
|
||||
import { RestartPolicy } from 'docker-types/generated/1.44';
|
||||
|
||||
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { SystemInfo, SystemVersion } from 'docker-types/generated/1.41';
|
||||
import { SystemInfo, SystemVersion } from 'docker-types/generated/1.44';
|
||||
|
||||
export const dockerHandlers = [
|
||||
http.get<never, never, SystemInfo>(
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"docker": "v28.3.0",
|
||||
"docker": "v29.1.2",
|
||||
"mingit": "2.49.0.1"
|
||||
}
|
||||
|
||||
+17
-2
@@ -59,9 +59,24 @@ ldflags="-s -X 'github.com/portainer/liblicense.LicenseServerBaseURL=https://api
|
||||
|
||||
echo "$ldflags"
|
||||
|
||||
GOOS=${1:-$(go env GOOS)} GOARCH=${2:-$(go env GOARCH)} CGO_ENABLED=0 go build \
|
||||
|
||||
# See: https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63
|
||||
# For a list of valid GOOS and GOARCH values
|
||||
PLATFORM=${1:-$(go env GOOS)}
|
||||
ARCH=${2:-$(go env GOARCH)}
|
||||
# if the default platform is darwin, set it to linux to allow it to run in the portainer/base image (which doesn't support darwin)
|
||||
if [ "$PLATFORM" = "darwin" ]; then
|
||||
PLATFORM="linux"
|
||||
fi
|
||||
|
||||
BINARY_NAME="portainer"
|
||||
if [ "$PLATFORM" = "windows" ]; then
|
||||
BINARY_NAME="portainer.exe"
|
||||
fi
|
||||
|
||||
GOOS=${PLATFORM} GOARCH=${ARCH} CGO_ENABLED=0 go build \
|
||||
-trimpath \
|
||||
--installsuffix cgo \
|
||||
--ldflags "$ldflags" \
|
||||
-o "../dist/portainer" \
|
||||
-o "../dist/${BINARY_NAME}" \
|
||||
./cmd/portainer/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/portainer/portainer
|
||||
|
||||
go 1.24.9
|
||||
go 1.24.11
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
@@ -50,11 +50,11 @@ require (
|
||||
github.com/urfave/negroni v1.0.0
|
||||
github.com/viney-shih/go-lock v1.1.1
|
||||
go.etcd.io/bbolt v1.4.3
|
||||
golang.org/x/crypto v0.40.0
|
||||
golang.org/x/crypto v0.45.0
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
|
||||
golang.org/x/mod v0.27.0
|
||||
golang.org/x/mod v0.29.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/sync v0.18.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
helm.sh/helm/v3 v3.18.5
|
||||
@@ -111,9 +111,9 @@ require (
|
||||
github.com/cloudflare/cfssl v1.6.4 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/containerd/console v1.0.5 // indirect
|
||||
github.com/containerd/containerd v1.7.27 // indirect
|
||||
github.com/containerd/containerd v1.7.29 // indirect
|
||||
github.com/containerd/containerd/api v1.9.0 // indirect
|
||||
github.com/containerd/containerd/v2 v2.1.4 // indirect
|
||||
github.com/containerd/containerd/v2 v2.1.5 // indirect
|
||||
github.com/containerd/continuity v0.4.5 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
@@ -292,11 +292,11 @@ require (
|
||||
go.uber.org/mock v0.6.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/term v0.33.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
|
||||
@@ -144,12 +144,12 @@ github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJ
|
||||
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
|
||||
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
|
||||
github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||
github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
|
||||
github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
|
||||
github.com/containerd/containerd v1.7.29 h1:90fWABQsaN9mJhGkoVnuzEY+o1XDPbg9BTC9QTAHnuE=
|
||||
github.com/containerd/containerd v1.7.29/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs=
|
||||
github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0=
|
||||
github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI=
|
||||
github.com/containerd/containerd/v2 v2.1.4 h1:/hXWjiSFd6ftrBOBGfAZ6T30LJcx1dBjdKEeI8xucKQ=
|
||||
github.com/containerd/containerd/v2 v2.1.4/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM=
|
||||
github.com/containerd/containerd/v2 v2.1.5 h1:pWSmPxUszaLZKQPvOx27iD4iH+aM6o0BoN9+hg77cro=
|
||||
github.com/containerd/containerd/v2 v2.1.5/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM=
|
||||
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
|
||||
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
@@ -865,8 +865,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
@@ -876,8 +876,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -898,8 +898,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
@@ -916,8 +916,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -953,8 +953,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -966,8 +966,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
|
||||
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -982,10 +982,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
@@ -994,8 +994,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
"author": "Portainer.io",
|
||||
"name": "portainer",
|
||||
"homepage": "http://portainer.io",
|
||||
"version": "2.33.3",
|
||||
"version": "2.33.6",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:portainer/portainer.git"
|
||||
@@ -92,7 +92,7 @@
|
||||
"codemirror-json-schema": "^0.8.0",
|
||||
"core-js": "^3.19.3",
|
||||
"date-fns": "^2.29.3",
|
||||
"docker-types": "^1.43.1",
|
||||
"docker-types": "^1.45.0",
|
||||
"fast-json-patch": "^3.1.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"filesize": "~3.3.0",
|
||||
|
||||
@@ -124,7 +124,11 @@ func (c *ComposeDeployer) Deploy(ctx context.Context, filePaths []string, option
|
||||
|
||||
project = project.WithoutUnnecessaryResources()
|
||||
|
||||
var opts api.UpOptions
|
||||
opts := api.UpOptions{
|
||||
Start: api.StartOptions{
|
||||
Project: project,
|
||||
},
|
||||
}
|
||||
if options.ForceRecreate {
|
||||
opts.Create.Recreate = api.RecreateForce
|
||||
}
|
||||
|
||||
@@ -80,6 +80,65 @@ services:
|
||||
require.False(t, containerExists(composeContainerName))
|
||||
}
|
||||
|
||||
// Detect regression in container injections.
|
||||
// Ref BE-12432
|
||||
// Ref https://github.com/portainer/portainer/issues/12909
|
||||
func Test_UpAndDownWithInjection(t *testing.T) {
|
||||
const content = `
|
||||
services:
|
||||
test:
|
||||
image: alpine:latest
|
||||
container_name: "composetest_alpine"
|
||||
command: ["sh", "-c", "cat /test.txt"]
|
||||
configs:
|
||||
- source: test-config
|
||||
target: /test.txt
|
||||
|
||||
configs:
|
||||
test-config:
|
||||
content: |
|
||||
Hello from inline config!
|
||||
This should appear in the container.
|
||||
`
|
||||
const projectName = "composetest"
|
||||
const containerName = "composetest_alpine"
|
||||
w := NewComposeDeployer()
|
||||
|
||||
dir := t.TempDir()
|
||||
ctx := context.Background()
|
||||
|
||||
filePath := createFile(t, dir, "docker-compose.yml", content)
|
||||
filePaths := []string{filePath}
|
||||
|
||||
err := w.Validate(ctx, filePaths, libstack.Options{ProjectName: projectName})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = w.Pull(ctx, filePaths, libstack.Options{ProjectName: projectName})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.False(t, containerExists(containerName))
|
||||
|
||||
err = w.Deploy(ctx, filePaths, libstack.DeployOptions{
|
||||
Options: libstack.Options{
|
||||
ProjectName: projectName,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, containerExists(containerName))
|
||||
|
||||
waitResult := w.WaitForStatus(ctx, projectName, libstack.StatusCompleted)
|
||||
|
||||
require.Empty(t, waitResult.ErrorMsg)
|
||||
require.Equal(t, libstack.StatusCompleted, waitResult.Status)
|
||||
|
||||
err = w.Remove(ctx, projectName, filePaths, libstack.RemoveOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.False(t, containerExists(containerName))
|
||||
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
w := NewComposeDeployer()
|
||||
|
||||
|
||||
@@ -9593,10 +9593,10 @@ dns-packet@^5.2.2:
|
||||
dependencies:
|
||||
"@leichtgewicht/ip-codec" "^2.0.1"
|
||||
|
||||
docker-types@^1.43.1:
|
||||
version "1.43.1"
|
||||
resolved "https://registry.yarnpkg.com/docker-types/-/docker-types-1.43.1.tgz#3f1a644e29c85392e95c207bba15f16b675dca2a"
|
||||
integrity sha512-eiihBU5LvZlNaeh/hGycsaoeutlPJ/0vyvEKvuBWnyilCq+IRWnv9e2+oh6AIpXEuHiWFowwHXmIlKlt07X3Mw==
|
||||
docker-types@^1.45.0:
|
||||
version "1.45.0"
|
||||
resolved "https://registry.yarnpkg.com/docker-types/-/docker-types-1.45.0.tgz#57f9eeb283364128fa472d25abc75563160aea4f"
|
||||
integrity sha512-IvVAmwGbXVSEsD+Ld3pwIhCSm4YbnlZ9dPHbDVkgZUcE22MSkuIARREc7ipQ9JoMOzu7qMPD8H/KCpGnrZRo7A==
|
||||
|
||||
doctrine@^2.1.0:
|
||||
version "2.1.0"
|
||||
|
||||
Reference in New Issue
Block a user