2023-07-13 07:47:20 +00:00
|
|
|
import _ from 'lodash';
|
2023-07-10 15:56:12 +00:00
|
|
|
import { getUniqueTagListFromImages } from '@/react/docker/images/utils';
|
2019-03-21 05:46:49 +00:00
|
|
|
import { ImageViewModel } from '../models/image';
|
2020-04-10 21:54:53 +00:00
|
|
|
import { ImageDetailsViewModel } from '../models/imageDetails';
|
|
|
|
import { ImageLayerViewModel } from '../models/imageLayer';
|
|
|
|
|
|
|
|
angular.module('portainer.docker').factory('ImageService', [
|
|
|
|
'$q',
|
|
|
|
'Image',
|
|
|
|
'ImageHelper',
|
|
|
|
'RegistryService',
|
|
|
|
'HttpRequestHelper',
|
|
|
|
'ContainerService',
|
|
|
|
'FileUploadService',
|
2018-07-26 13:09:48 +00:00
|
|
|
function ImageServiceFactory($q, Image, ImageHelper, RegistryService, HttpRequestHelper, ContainerService, FileUploadService) {
|
2020-04-10 21:54:53 +00:00
|
|
|
'use strict';
|
|
|
|
var service = {};
|
|
|
|
|
|
|
|
service.image = function (imageId) {
|
|
|
|
var deferred = $q.defer();
|
|
|
|
Image.get({ id: imageId })
|
|
|
|
.$promise.then(function success(data) {
|
|
|
|
if (data.message) {
|
|
|
|
deferred.reject({ msg: data.message });
|
|
|
|
} else {
|
|
|
|
var image = new ImageDetailsViewModel(data);
|
|
|
|
deferred.resolve(image);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
deferred.reject({ msg: 'Unable to retrieve image details', err: err });
|
|
|
|
});
|
|
|
|
return deferred.promise;
|
|
|
|
};
|
|
|
|
|
2023-10-11 07:26:44 +00:00
|
|
|
service.images = function ({ environmentId, withUsage } = {}) {
|
2020-04-10 21:54:53 +00:00
|
|
|
var deferred = $q.defer();
|
|
|
|
|
|
|
|
$q.all({
|
2023-10-11 07:26:44 +00:00
|
|
|
containers: withUsage ? ContainerService.containers(environmentId, 1) : [],
|
2020-04-10 21:54:53 +00:00
|
|
|
images: Image.query({}).$promise,
|
|
|
|
})
|
|
|
|
.then(function success(data) {
|
|
|
|
var containers = data.containers;
|
2023-07-13 07:47:20 +00:00
|
|
|
const containerByImageId = _.groupBy(containers, 'ImageID');
|
2020-04-10 21:54:53 +00:00
|
|
|
|
|
|
|
var images = data.images.map(function (item) {
|
2023-07-13 07:47:20 +00:00
|
|
|
item.Used = !!containerByImageId[item.Id] && containerByImageId[item.Id].length > 0;
|
2020-04-10 21:54:53 +00:00
|
|
|
return new ImageViewModel(item);
|
|
|
|
});
|
|
|
|
|
|
|
|
deferred.resolve(images);
|
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
deferred.reject({ msg: 'Unable to retrieve images', err: err });
|
|
|
|
});
|
|
|
|
return deferred.promise;
|
|
|
|
};
|
|
|
|
|
|
|
|
service.history = function (imageId) {
|
|
|
|
var deferred = $q.defer();
|
|
|
|
Image.history({ id: imageId })
|
|
|
|
.$promise.then(function success(data) {
|
|
|
|
if (data.message) {
|
|
|
|
deferred.reject({ msg: data.message });
|
|
|
|
} else {
|
|
|
|
var layers = [];
|
|
|
|
var order = data.length;
|
|
|
|
angular.forEach(data, function (imageLayer) {
|
|
|
|
layers.push(new ImageLayerViewModel(order, imageLayer));
|
|
|
|
order--;
|
|
|
|
});
|
|
|
|
deferred.resolve(layers);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
deferred.reject({ msg: 'Unable to retrieve image details', err: err });
|
|
|
|
});
|
|
|
|
return deferred.promise;
|
|
|
|
};
|
|
|
|
|
|
|
|
service.pushImage = pushImage;
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {PorImageRegistryModel} registryModel
|
|
|
|
*/
|
|
|
|
function pushImage(registryModel) {
|
|
|
|
var deferred = $q.defer();
|
|
|
|
|
|
|
|
var authenticationDetails = registryModel.Registry.Authentication ? RegistryService.encodedCredentials(registryModel.Registry) : '';
|
|
|
|
HttpRequestHelper.setRegistryAuthenticationHeader(authenticationDetails);
|
|
|
|
|
|
|
|
const imageConfiguration = ImageHelper.createImageConfigForContainer(registryModel);
|
|
|
|
|
|
|
|
Image.push({ imageName: imageConfiguration.fromImage })
|
|
|
|
.$promise.then(function success(data) {
|
|
|
|
if (data[data.length - 1].error) {
|
|
|
|
deferred.reject({ msg: data[data.length - 1].error });
|
|
|
|
} else {
|
|
|
|
deferred.resolve();
|
2017-08-24 05:53:34 +00:00
|
|
|
}
|
2020-04-10 21:54:53 +00:00
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
deferred.reject({ msg: 'Unable to push image tag', err: err });
|
|
|
|
});
|
|
|
|
return deferred.promise;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* PULL IMAGE
|
|
|
|
*/
|
|
|
|
|
|
|
|
function pullImageAndIgnoreErrors(imageConfiguration) {
|
|
|
|
var deferred = $q.defer();
|
|
|
|
|
2020-07-30 18:24:34 +00:00
|
|
|
Image.create({}, imageConfiguration)
|
|
|
|
.$promise.catch(() => {
|
|
|
|
// left empty to ignore errors
|
|
|
|
})
|
|
|
|
.finally(function final() {
|
|
|
|
deferred.resolve();
|
|
|
|
});
|
2017-08-24 05:53:34 +00:00
|
|
|
|
2020-04-10 21:54:53 +00:00
|
|
|
return deferred.promise;
|
|
|
|
}
|
|
|
|
|
|
|
|
function pullImageAndAcknowledgeErrors(imageConfiguration) {
|
|
|
|
var deferred = $q.defer();
|
|
|
|
|
|
|
|
Image.create({}, imageConfiguration)
|
|
|
|
.$promise.then(function success(data) {
|
2021-08-24 04:34:18 +00:00
|
|
|
var err = data.length > 0 && data[data.length - 1].message;
|
2020-04-10 21:54:53 +00:00
|
|
|
if (err) {
|
|
|
|
var detail = data[data.length - 1];
|
|
|
|
deferred.reject({ msg: detail.message });
|
|
|
|
} else {
|
|
|
|
deferred.resolve(data);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
deferred.reject({ msg: 'Unable to pull image', err: err });
|
2017-07-08 06:59:32 +00:00
|
|
|
});
|
2017-03-20 11:01:35 +00:00
|
|
|
|
2020-04-10 21:54:53 +00:00
|
|
|
return deferred.promise;
|
|
|
|
}
|
2017-06-29 14:05:39 +00:00
|
|
|
|
2020-04-10 21:54:53 +00:00
|
|
|
service.pullImage = pullImage;
|
2019-11-27 22:36:39 +00:00
|
|
|
|
2020-04-10 21:54:53 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {PorImageRegistryModel} registry
|
|
|
|
* @param {bool} ignoreErrors
|
|
|
|
*/
|
|
|
|
function pullImage(registry, ignoreErrors) {
|
|
|
|
var authenticationDetails = registry.Registry.Authentication ? RegistryService.encodedCredentials(registry.Registry) : '';
|
|
|
|
HttpRequestHelper.setRegistryAuthenticationHeader(authenticationDetails);
|
2017-06-29 14:05:39 +00:00
|
|
|
|
2020-04-10 21:54:53 +00:00
|
|
|
var imageConfiguration = ImageHelper.createImageConfigForContainer(registry);
|
2019-11-27 22:36:39 +00:00
|
|
|
|
2020-04-10 21:54:53 +00:00
|
|
|
if (ignoreErrors) {
|
|
|
|
return pullImageAndIgnoreErrors(imageConfiguration);
|
2017-03-20 11:01:35 +00:00
|
|
|
}
|
2020-04-10 21:54:53 +00:00
|
|
|
return pullImageAndAcknowledgeErrors(imageConfiguration);
|
|
|
|
}
|
2017-11-20 13:34:14 +00:00
|
|
|
|
2020-04-10 21:54:53 +00:00
|
|
|
/**
|
|
|
|
* ! PULL IMAGE
|
|
|
|
*/
|
|
|
|
|
|
|
|
service.tagImage = function (id, image) {
|
|
|
|
return Image.tag({ id: id, repo: image }).$promise;
|
|
|
|
};
|
|
|
|
|
2024-03-05 17:30:45 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Array<{tags: Array<string>; id: string;}>} images
|
|
|
|
* @returns {Promise<unknown>}
|
|
|
|
*/
|
2020-04-10 21:54:53 +00:00
|
|
|
service.downloadImages = function (images) {
|
|
|
|
var names = ImageHelper.getImagesNamesForDownload(images);
|
|
|
|
return Image.download(names).$promise;
|
|
|
|
};
|
|
|
|
|
|
|
|
service.uploadImage = function (file) {
|
|
|
|
return FileUploadService.loadImages(file);
|
|
|
|
};
|
|
|
|
|
|
|
|
service.deleteImage = function (id, forceRemoval) {
|
|
|
|
var deferred = $q.defer();
|
|
|
|
Image.remove({ id: id, force: forceRemoval })
|
|
|
|
.$promise.then(function success(data) {
|
|
|
|
if (data[0].message) {
|
|
|
|
deferred.reject({ msg: data[0].message });
|
|
|
|
} else {
|
|
|
|
deferred.resolve();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
deferred.reject({ msg: 'Unable to remove image', err: err });
|
|
|
|
});
|
|
|
|
return deferred.promise;
|
|
|
|
};
|
|
|
|
|
2023-07-10 15:56:12 +00:00
|
|
|
service.getUniqueTagListFromImages = getUniqueTagListFromImages;
|
2020-04-10 21:54:53 +00:00
|
|
|
|
|
|
|
return service;
|
|
|
|
},
|
|
|
|
]);
|