You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dlab.apache.org by of...@apache.org on 2020/04/23 08:22:39 UTC

[incubator-dlab] 01/01: gcp bucket browser

This is an automated email from the ASF dual-hosted git repository.

ofuks pushed a commit to branch bucket-browser-gcp
in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git

commit 6c28123370488f391010405aa105a6d8d8239c8e
Author: Oleh Fuks <ol...@gmail.com>
AuthorDate: Mon Apr 13 18:48:54 2020 +0300

    gcp bucket browser
---
 .../src/ssn/templates/ssn.yml                      |   5 +
 .../java/com/epam/dlab/dto/bucket/BucketDTO.java}  |  22 ++--
 .../epam/dlab/dto/bucket/BucketDownloadDTO.java}   |  21 ++--
 services/dlab-webapp-common/pom.xml                |   5 +
 .../java/com/epam/dlab/ServiceConfiguration.java   |   9 ++
 .../com/epam/dlab/constants/ServiceConsts.java     |   1 +
 .../com/epam/dlab/rest/client/RESTService.java     |  78 ++++++++++---
 .../epam/dlab/rest/client/RESTServiceFactory.java  |   5 +-
 services/provisioning-service/pom.xml              |  27 +++++
 .../backendapi/ProvisioningServiceApplication.java |  34 ++++--
 .../backendapi/modules/GcpProvisioningModule.java  |   1 +
 .../dlab/backendapi/modules/ProductionModule.java  |  26 +++--
 .../backendapi/modules/ProvisioningDevModule.java  |  31 ++---
 .../dlab/backendapi/resources/BucketResource.java  | 101 ++++++++++++++++
 .../dlab/backendapi/service/BucketService.java}    |  23 ++--
 .../service/impl/gcp/BucketServiceGcpImpl.java     | 109 +++++++++++++++++
 .../backendapi/modules/CloudProviderModule.java    |   2 +
 .../epam/dlab/backendapi/modules/DevModule.java    |  89 +++++++++++---
 .../dlab/backendapi/modules/ProductionModule.java  |  93 ++++++++++++---
 .../dlab/backendapi/resources/BucketResource.java  | 101 ++++++++++++++++
 .../resources/dto/BucketDownloadDTO.java}          |  23 ++--
 .../dlab/backendapi/service/BucketService.java}    |  24 ++--
 .../backendapi/service/impl/BucketServiceImpl.java | 129 +++++++++++++++++++++
 .../InfrastructureTemplateServiceBaseTest.java     |  28 +++--
 24 files changed, 848 insertions(+), 139 deletions(-)

diff --git a/infrastructure-provisioning/src/ssn/templates/ssn.yml b/infrastructure-provisioning/src/ssn/templates/ssn.yml
index fffa7d2..949ddf9 100644
--- a/infrastructure-provisioning/src/ssn/templates/ssn.yml
+++ b/infrastructure-provisioning/src/ssn/templates/ssn.yml
@@ -62,5 +62,10 @@ provisioningService:
     timeout: 3s
     connectionTimeout: 3s
 
+bucketService:
+  jerseyClient:
+    timeout: 5m
+    connectionTimeout: 3s
+
 # Log out user on inactivity
 inactiveUserTimeoutMillSec: 7200000
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDTO.java
similarity index 61%
copy from services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
copy to services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDTO.java
index d376665..5f260b7 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDTO.java
@@ -17,16 +17,18 @@
  * under the License.
  */
 
-package com.epam.dlab.constants;
+package com.epam.dlab.dto.bucket;
 
-public final class ServiceConsts {
-	public static final String MONGO_NAME = "mongo";
-	public static final String PROVISIONING_SERVICE_NAME = "provisioningService";
-	public static final String MAVEN_SEARCH_API = "mavenSearchService";
-	public static final String SECURITY_SERVICE_NAME = "securityService";
-	public static final String SELF_SERVICE_NAME = "selfService";
-	public static final String PROVISIONING_USER_AGENT = "provisioning-service";
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Builder;
+import lombok.Data;
 
-	private ServiceConsts() {
-	}
+@Data
+@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BucketDTO {
+    private final String bucket;
+    private final String object;
+    private final String size;
+    private final String creationDate;
 }
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDownloadDTO.java
similarity index 61%
copy from services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
copy to services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDownloadDTO.java
index d376665..b1201e6 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDownloadDTO.java
@@ -17,16 +17,17 @@
  * under the License.
  */
 
-package com.epam.dlab.constants;
+package com.epam.dlab.dto.bucket;
 
-public final class ServiceConsts {
-	public static final String MONGO_NAME = "mongo";
-	public static final String PROVISIONING_SERVICE_NAME = "provisioningService";
-	public static final String MAVEN_SEARCH_API = "mavenSearchService";
-	public static final String SECURITY_SERVICE_NAME = "securityService";
-	public static final String SELF_SERVICE_NAME = "selfService";
-	public static final String PROVISIONING_USER_AGENT = "provisioning-service";
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
 
-	private ServiceConsts() {
-	}
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BucketDownloadDTO {
+    @NotBlank(message = "field cannot be empty")
+    private final String bucket;
+    @NotBlank(message = "field cannot be empty")
+    private final String object;
 }
diff --git a/services/dlab-webapp-common/pom.xml b/services/dlab-webapp-common/pom.xml
index 6c846d6..2e7ad5c 100644
--- a/services/dlab-webapp-common/pom.xml
+++ b/services/dlab-webapp-common/pom.xml
@@ -57,6 +57,11 @@
             <version>${io.dropwizard.version}</version>
         </dependency>
         <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-forms</artifactId>
+            <version>${io.dropwizard.version}</version>
+        </dependency>
+        <dependency>
             <groupId>com.epam.dlab</groupId>
             <artifactId>common</artifactId>
         </dependency>
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/ServiceConfiguration.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/ServiceConfiguration.java
index 85d4318..51b0779 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/ServiceConfiguration.java
+++ b/services/dlab-webapp-common/src/main/java/com/epam/dlab/ServiceConfiguration.java
@@ -54,6 +54,11 @@ public class ServiceConfiguration extends Configuration {
 
     @Valid
     @NotNull
+    @JsonProperty(ServiceConsts.BUCKET_SERVICE_NAME)
+    private RESTServiceFactory bucketFactory = new RESTServiceFactory();
+
+    @Valid
+    @NotNull
     @JsonProperty(ServiceConsts.SECURITY_SERVICE_NAME)
     private RESTServiceFactory securityFactory;
 
@@ -85,6 +90,10 @@ public class ServiceConfiguration extends Configuration {
         return provisioningFactory;
     }
 
+    public RESTServiceFactory getBucketFactory() {
+        return bucketFactory;
+    }
+
     public RESTServiceFactory getSecurityFactory() {
         return securityFactory;
     }
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
index d376665..d7d7208 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
+++ b/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
@@ -22,6 +22,7 @@ package com.epam.dlab.constants;
 public final class ServiceConsts {
 	public static final String MONGO_NAME = "mongo";
 	public static final String PROVISIONING_SERVICE_NAME = "provisioningService";
+	public static final String BUCKET_SERVICE_NAME = "bucketService";
 	public static final String MAVEN_SEARCH_API = "mavenSearchService";
 	public static final String SECURITY_SERVICE_NAME = "securityService";
 	public static final String SELF_SERVICE_NAME = "selfService";
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTService.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTService.java
index ab1d29e..924862c 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTService.java
+++ b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTService.java
@@ -19,21 +19,24 @@
 
 package com.epam.dlab.rest.client;
 
-import com.epam.dlab.exceptions.DlabException;
 import lombok.extern.slf4j.Slf4j;
+import org.glassfish.jersey.media.multipart.Boundary;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
 
-import javax.ws.rs.ProcessingException;
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.Invocation;
 import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
-import java.net.ConnectException;
 import java.net.URI;
 import java.util.Collections;
 import java.util.Map;
 
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA_TYPE;
+
 @Slf4j
 public class RESTService {
 	private Client client;
@@ -65,42 +68,75 @@ public class RESTService {
 				.get(clazz);
 	}
 
+	public <T> T getWithMediaTypes(String path, String accessToken, Class<T> clazz, String requestMediaType, String acceptMediaType) {
+		return get(path, accessToken, clazz, requestMediaType, acceptMediaType);
+	}
+
 	public <T> T get(String path, String accessToken, Class<T> clazz) {
-		Invocation.Builder builder = getBuilder(path, accessToken, Collections.emptyMap());
+		return get(path, accessToken, clazz, APPLICATION_JSON, APPLICATION_JSON);
+	}
+
+	private <T> T get(String path, String accessToken, Class<T> clazz, String requestMediaType, String acceptMediaType) {
+		Invocation.Builder builder = getBuilder(path, accessToken, Collections.emptyMap(), requestMediaType, acceptMediaType);
 		log.debug("REST get secured {} {}", path, accessToken);
 		return builder.get(clazz);
 	}
 
+	public <T> T get(String path, GenericType<T> genericType) {
+		return get(path, null, genericType);
+	}
+
+	public <T> T get(String path, String accessToken, GenericType<T> genericType) {
+		return get(path, accessToken, genericType, Collections.emptyMap());
+	}
+
+	public <T> T get(String path, String accessToken, GenericType<T> genericType, Map<String, Object> queryParams) {
+		Invocation.Builder builder = getBuilder(path, accessToken, queryParams, APPLICATION_JSON, APPLICATION_JSON);
+		log.debug("REST get secured {} {}", path, accessToken);
+		return builder.get(genericType);
+	}
+
 	public <T> T post(String path, Object parameter, Class<T> clazz) {
 		return post(path, null, parameter, clazz);
 	}
 
 	public <T> T post(String path, String accessToken, Object parameter, Class<T> clazz) {
-		return post(path, accessToken, parameter, clazz, Collections.emptyMap());
+		return post(path, accessToken, parameter, clazz, Collections.emptyMap(), APPLICATION_JSON, APPLICATION_JSON);
+	}
+
+	public <T> T delete(String path, String accessToken, Class<T> clazz, String requestMediaType, String acceptMediaType) {
+		return delete(path, accessToken, clazz, Collections.emptyMap(), requestMediaType, acceptMediaType);
 	}
 
-	public <T> T post(String path, String accessToken, Object parameter, Class<T> clazz,
-					  Map<String, Object> queryParams) {
-		Invocation.Builder builder = getBuilder(path, accessToken, queryParams);
+	private <T> T delete(String path, String accessToken, Class<T> clazz, Map<String, Object> queryParams,
+						 String requestMediaType, String acceptMediaType) {
+		Invocation.Builder builder = getBuilder(path, accessToken, queryParams, requestMediaType, acceptMediaType);
+		log.debug("REST delete secured {} {}", path, accessToken);
+		return builder.delete(clazz);
+	}
+
+	private <T> T post(String path, String accessToken, Object parameter, Class<T> clazz, Map<String, Object> queryParams,
+					   String requestMediaType, String acceptMediaType) {
+		Invocation.Builder builder = getBuilder(path, accessToken, queryParams, requestMediaType, acceptMediaType);
 		log.debug("REST post secured {} {}", path, accessToken);
 		return builder.post(Entity.json(parameter), clazz);
 	}
 
 
-	private Invocation.Builder getBuilder(String path, String token, Map<String, Object> queryParams) {
+	private Invocation.Builder getBuilder(String path, String token, Map<String, Object> queryParams,
+										  String requestMediaType, String acceptMediaType) {
 		WebTarget webTarget = getWebTarget(path);
 		for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
 			webTarget = webTarget.queryParam(entry.getKey(), entry.getValue());
 		}
 
 		Invocation.Builder builder = webTarget
-				.request(MediaType.APPLICATION_JSON)
-				.accept(MediaType.APPLICATION_JSON);
+				.request(requestMediaType)
+				.accept(acceptMediaType);
 
 		if (token != null) {
 			builder.header(HttpHeaders.AUTHORIZATION, "Bearer " + token);
 		}
-
 		if (userAgent != null) {
 			builder.header(HttpHeaders.USER_AGENT, userAgent);
 		}
@@ -108,8 +144,22 @@ public class RESTService {
 		return builder;
 	}
 
+	public <T> T postForm(String path, String token, FormDataMultiPart form, Class<T> clazz) {
+		WebTarget webTarget = getWebTarget(path);
+		Invocation.Builder builder = webTarget.request();
+		if (token != null) {
+			builder.header(HttpHeaders.AUTHORIZATION, "Bearer " + token);
+		}
+		if (userAgent != null) {
+			builder.header(HttpHeaders.USER_AGENT, userAgent);
+		}
+
+		MediaType mediaType = Boundary.addBoundary(MULTIPART_FORM_DATA_TYPE);
+		return builder.post(Entity.entity(form, mediaType), clazz);
+	}
+
+
 	private WebTarget getWebTarget(String path) {
-		return url != null ?
-				client.target(url).path(path) : client.target(path);
+		return url != null ? client.target(url).path(path) : client.target(path);
 	}
 }
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTServiceFactory.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTServiceFactory.java
index a7aa942..aeb0ad1 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTServiceFactory.java
+++ b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTServiceFactory.java
@@ -24,10 +24,9 @@ import io.dropwizard.client.JerseyClientBuilder;
 import io.dropwizard.client.JerseyClientConfiguration;
 import io.dropwizard.setup.Environment;
 import org.apache.commons.lang3.StringUtils;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
 
 import javax.validation.Valid;
-import javax.validation.constraints.Max;
-import javax.validation.constraints.Min;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.client.Client;
 
@@ -51,7 +50,7 @@ public class RESTServiceFactory {
 	}
 
 	public RESTService build(Environment environment, String name, String userAgent) {
-		Client client = new JerseyClientBuilder(environment).using(jerseyClientConfiguration).build(name);
+		Client client = new JerseyClientBuilder(environment).using(jerseyClientConfiguration).build(name).register(MultiPartFeature.class);
 		return StringUtils.isNotEmpty(host) ?
 				new RESTService(client, getURL(), userAgent) : new RESTService(client, userAgent);
 	}
diff --git a/services/provisioning-service/pom.xml b/services/provisioning-service/pom.xml
index 1a6548e..78bc19b 100644
--- a/services/provisioning-service/pom.xml
+++ b/services/provisioning-service/pom.xml
@@ -29,6 +29,18 @@
 
     <artifactId>provisioning-service</artifactId>
 
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>com.google.cloud</groupId>
+                <artifactId>libraries-bom</artifactId>
+                <version>3.3.0</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
     <dependencies>
         <dependency>
             <groupId>com.epam.dlab</groupId>
@@ -63,8 +75,23 @@
             <artifactId>conveyor</artifactId>
             <version>${com.aegisql.conveyor.version}</version>
         </dependency>
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-forms</artifactId>
+            <version>${io.dropwizard.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.cloud</groupId>
+            <artifactId>google-cloud-storage</artifactId>
+            <version>1.106.0</version>
+        </dependency>
 
         <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.6</version>
+        </dependency>
+        <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
             <version>${org.mockito.version}</version>
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java
index 6f1047b..fbb5f5a 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java
@@ -26,7 +26,16 @@ import com.epam.dlab.backendapi.core.DockerWarmuper;
 import com.epam.dlab.backendapi.core.response.handlers.ComputationalConfigure;
 import com.epam.dlab.backendapi.modules.CloudModuleConfigurator;
 import com.epam.dlab.backendapi.modules.ModuleFactory;
-import com.epam.dlab.backendapi.resources.*;
+import com.epam.dlab.backendapi.resources.BackupResource;
+import com.epam.dlab.backendapi.resources.BucketResource;
+import com.epam.dlab.backendapi.resources.CallbackHandlerResource;
+import com.epam.dlab.backendapi.resources.DockerResource;
+import com.epam.dlab.backendapi.resources.GitExploratoryResource;
+import com.epam.dlab.backendapi.resources.ImageResource;
+import com.epam.dlab.backendapi.resources.InfrastructureResource;
+import com.epam.dlab.backendapi.resources.LibraryResource;
+import com.epam.dlab.backendapi.resources.ProjectResource;
+import com.epam.dlab.backendapi.resources.ProvisioningHealthCheckResource;
 import com.epam.dlab.backendapi.resources.base.KeyResource;
 import com.epam.dlab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
 import com.epam.dlab.cloud.CloudModule;
@@ -47,6 +56,7 @@ import de.thomaskrille.dropwizard_template_config.TemplateConfigBundleConfigurat
 import io.dropwizard.Application;
 import io.dropwizard.auth.Authenticator;
 import io.dropwizard.auth.Authorizer;
+import io.dropwizard.forms.MultiPartBundle;
 import io.dropwizard.jersey.setup.JerseyEnvironment;
 import io.dropwizard.setup.Bootstrap;
 import io.dropwizard.setup.Environment;
@@ -66,16 +76,17 @@ public class ProvisioningServiceApplication extends Application<ProvisioningServ
 
 	@Override
 	public void initialize(Bootstrap<ProvisioningServiceApplicationConfiguration> bootstrap) {
-		bootstrap.addBundle(new TemplateConfigBundle(
-				new TemplateConfigBundleConfiguration().fileIncludePath(ServiceUtils.getConfPath())
-		));
-		bootstrap.addBundle(new KeycloakBundle<ProvisioningServiceApplicationConfiguration>() {
-			@Override
-			protected KeycloakConfiguration getKeycloakConfiguration(ProvisioningServiceApplicationConfiguration configuration) {
-				return configuration.getKeycloakConfiguration();
-			}
-
-			@Override
+        bootstrap.addBundle(new MultiPartBundle());
+        bootstrap.addBundle(new TemplateConfigBundle(
+                new TemplateConfigBundleConfiguration().fileIncludePath(ServiceUtils.getConfPath())
+        ));
+        bootstrap.addBundle(new KeycloakBundle<ProvisioningServiceApplicationConfiguration>() {
+            @Override
+            protected KeycloakConfiguration getKeycloakConfiguration(ProvisioningServiceApplicationConfiguration configuration) {
+                return configuration.getKeycloakConfiguration();
+            }
+
+            @Override
 			protected Class<? extends Principal> getUserClass() {
 				return UserInfo.class;
 			}
@@ -145,5 +156,6 @@ public class ProvisioningServiceApplication extends Application<ProvisioningServ
 		jersey.register(injector.getInstance(CallbackHandlerResource.class));
 		jersey.register(injector.getInstance(ProjectResource.class));
 		jersey.register(injector.getInstance(ProvisioningHealthCheckResource.class));
+		environment.jersey().register(injector.getInstance(BucketResource.class));
 	}
 }
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/GcpProvisioningModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/GcpProvisioningModule.java
index 4553592..1365c33 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/GcpProvisioningModule.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/GcpProvisioningModule.java
@@ -19,6 +19,7 @@
 
 package com.epam.dlab.backendapi.modules;
 
+import com.epam.dlab.backendapi.resources.BucketResource;
 import com.epam.dlab.backendapi.resources.gcp.ComputationalResourceGcp;
 import com.epam.dlab.backendapi.resources.gcp.EdgeResourceGcp;
 import com.epam.dlab.backendapi.resources.gcp.ExploratoryResourceGcp;
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
index 40744fa..d01ebc5 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
@@ -27,12 +27,15 @@ import com.epam.dlab.backendapi.core.commands.CommandExecutor;
 import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
 import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
 import com.epam.dlab.backendapi.core.response.handlers.dao.FileSystemCallbackHandlerDao;
+import com.epam.dlab.backendapi.service.BucketService;
 import com.epam.dlab.backendapi.service.CheckInactivityService;
 import com.epam.dlab.backendapi.service.ProjectService;
 import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
 import com.epam.dlab.backendapi.service.impl.CheckInactivityServiceImpl;
 import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
 import com.epam.dlab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
+import com.epam.dlab.backendapi.service.impl.gcp.BucketServiceGcpImpl;
+import com.epam.dlab.cloud.CloudProvider;
 import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.rest.client.RESTService;
 import com.fasterxml.jackson.core.JsonParser;
@@ -64,14 +67,17 @@ public class ProductionModule extends ModuleBase<ProvisioningServiceApplicationC
 						.build(environment, ServiceConsts.SECURITY_SERVICE_NAME, ServiceConsts
 								.PROVISIONING_USER_AGENT));
 
-		bind(RESTService.class).toInstance(configuration.getSelfFactory().build(environment, ServiceConsts
-				.SELF_SERVICE_NAME));
-		bind(MetadataHolder.class).to(DockerWarmuper.class);
-		bind(ICommandExecutor.class).to(CommandExecutor.class).asEagerSingleton();
-		bind(ObjectMapper.class).toInstance(new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true));
-		bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
-		bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
-		bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
-		bind(ProjectService.class).to(ProjectServiceImpl.class);
-	}
+        bind(RESTService.class).toInstance(configuration.getSelfFactory().build(environment, ServiceConsts
+                .SELF_SERVICE_NAME));
+        bind(MetadataHolder.class).to(DockerWarmuper.class);
+        bind(ICommandExecutor.class).to(CommandExecutor.class).asEagerSingleton();
+        bind(ObjectMapper.class).toInstance(new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true));
+        bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
+        bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
+        bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
+        bind(ProjectService.class).to(ProjectServiceImpl.class);
+        if (configuration.getCloudProvider() == CloudProvider.GCP) {
+            bind(BucketService.class).to(BucketServiceGcpImpl.class);
+        }
+    }
 }
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
index 73d333f..43685a6 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
@@ -30,13 +30,15 @@ import com.epam.dlab.backendapi.core.commands.CommandExecutorMock;
 import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
 import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
 import com.epam.dlab.backendapi.core.response.handlers.dao.FileSystemCallbackHandlerDao;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
+import com.epam.dlab.backendapi.service.BucketService;
 import com.epam.dlab.backendapi.service.CheckInactivityService;
+import com.epam.dlab.backendapi.service.ProjectService;
 import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
 import com.epam.dlab.backendapi.service.impl.CheckInactivityServiceImpl;
 import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
 import com.epam.dlab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
+import com.epam.dlab.backendapi.service.impl.gcp.BucketServiceGcpImpl;
+import com.epam.dlab.cloud.CloudProvider;
 import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.rest.client.RESTService;
 import com.epam.dlab.rest.contracts.DockerAPI;
@@ -70,17 +72,20 @@ public class ProvisioningDevModule extends ModuleBase<ProvisioningServiceApplica
 	protected void configure() {
 		bind(ProvisioningServiceApplicationConfiguration.class).toInstance(configuration);
 		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.SECURITY_SERVICE_NAME)).toInstance
-				(createAuthenticationService());
-		bind(RESTService.class).toInstance(configuration.getSelfFactory().build(environment, ServiceConsts
-				.SELF_SERVICE_NAME));
-		bind(MetadataHolder.class).to(DockerWarmuper.class);
-		bind(ICommandExecutor.class).toInstance(new CommandExecutorMock(configuration.getCloudProvider()));
-		bind(ObjectMapper.class).toInstance(new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true));
-		bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
-		bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
-		bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
-		bind(ProjectService.class).to(ProjectServiceImpl.class);
-	}
+                (createAuthenticationService());
+        bind(RESTService.class).toInstance(configuration.getSelfFactory().build(environment, ServiceConsts
+                .SELF_SERVICE_NAME));
+        bind(MetadataHolder.class).to(DockerWarmuper.class);
+        bind(ICommandExecutor.class).toInstance(new CommandExecutorMock(configuration.getCloudProvider()));
+        bind(ObjectMapper.class).toInstance(new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true));
+        bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
+        bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
+        bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
+        bind(ProjectService.class).to(ProjectServiceImpl.class);
+        if (configuration.getCloudProvider() == CloudProvider.GCP) {
+            bind(BucketService.class).to(BucketServiceGcpImpl.class);
+        }
+    }
 
 	/**
 	 * Creates and returns the mock object for authentication service.
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java
new file mode 100644
index 0000000..7859a0a
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.resources;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.service.BucketService;
+import com.google.cloud.storage.Storage;
+import com.google.cloud.storage.StorageOptions;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+
+@Slf4j
+@Path("/bucket")
+public class BucketResource {
+    private final BucketService bucketService;
+
+    @Inject
+    public BucketResource(BucketService bucketService) {
+        this.bucketService = bucketService;
+    }
+
+    @GET
+    @Path("/{bucket}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getListOfObjects(@Auth UserInfo userInfo,
+                                     @PathParam("bucket") String bucket) {
+        return Response.ok(bucketService.getObjects(bucket)).build();
+    }
+
+    @POST
+    @Path("/upload")
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response uploadObject(@Auth UserInfo userInfo,
+                                 @FormDataParam("object") String object,
+                                 @FormDataParam("bucket") String bucket,
+                                 @FormDataParam("file") InputStream inputStream,
+                                 @FormDataParam("file") FormDataContentDisposition fileMetaData) {
+        bucketService.uploadObject(bucket, object, inputStream);
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/{bucket}/object/{object}/download")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_OCTET_STREAM)
+    public Response downloadObject(@Auth UserInfo userInfo,
+                                   @PathParam("object") String object,
+                                   @PathParam("bucket") String bucket) {
+        return Response.ok(bucketService.downloadObject(bucket, object)).build();
+    }
+
+    @DELETE
+    @Path("/{bucket}/object/{object}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response uploadObject(@Auth UserInfo userInfo,
+                                 @PathParam("bucket") String bucket,
+                                 @PathParam("object") String object) {
+        bucketService.deleteObject(bucket, object);
+        return Response.ok().build();
+    }
+
+    public static void main(String[] args) {
+        Storage storage = StorageOptions.getDefaultInstance().getService();
+        String bucketName = "ofuks-1304-prj1-local-bucket";
+        storage.delete(bucketName, "1.txt");
+    }
+}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
similarity index 61%
copy from services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
copy to services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
index d376665..772fd0d 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
@@ -17,16 +17,19 @@
  * under the License.
  */
 
-package com.epam.dlab.constants;
+package com.epam.dlab.backendapi.service;
 
-public final class ServiceConsts {
-	public static final String MONGO_NAME = "mongo";
-	public static final String PROVISIONING_SERVICE_NAME = "provisioningService";
-	public static final String MAVEN_SEARCH_API = "mavenSearchService";
-	public static final String SECURITY_SERVICE_NAME = "securityService";
-	public static final String SELF_SERVICE_NAME = "selfService";
-	public static final String PROVISIONING_USER_AGENT = "provisioning-service";
+import com.epam.dlab.dto.bucket.BucketDTO;
 
-	private ServiceConsts() {
-	}
+import java.io.InputStream;
+import java.util.List;
+
+public interface BucketService {
+    List<BucketDTO> getObjects(String bucket);
+
+    void uploadObject(String bucket, String object, InputStream stream);
+
+    byte[] downloadObject(String bucket, String object);
+
+    void deleteObject(String bucket, String object);
 }
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/gcp/BucketServiceGcpImpl.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/gcp/BucketServiceGcpImpl.java
new file mode 100644
index 0000000..6bc0a8d
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/gcp/BucketServiceGcpImpl.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.service.impl.gcp;
+
+import com.epam.dlab.backendapi.service.BucketService;
+import com.epam.dlab.dto.bucket.BucketDTO;
+import com.epam.dlab.exceptions.DlabException;
+import com.google.cloud.storage.Blob;
+import com.google.cloud.storage.BlobId;
+import com.google.cloud.storage.BlobInfo;
+import com.google.cloud.storage.Bucket;
+import com.google.cloud.storage.Storage;
+import com.google.cloud.storage.StorageOptions;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+@Slf4j
+public class BucketServiceGcpImpl implements BucketService {
+
+    @Override
+    public List<BucketDTO> getObjects(String bucket) {
+        try {
+            Storage storage = StorageOptions.getDefaultInstance().getService();
+            Bucket gcpBucket = storage.get(bucket);
+            return StreamSupport.stream(gcpBucket.list().getValues().spliterator(), false)
+                    .map(this::toBucketDTO)
+                    .collect(Collectors.toList());
+        } catch (Exception e) {
+            log.error("Cannot retrieve objects from bucket {}. Reason: {}", bucket, e.getMessage());
+            throw new DlabException(String.format("Cannot retrieve objects from bucket %s. Reason: %s", bucket, e.getMessage()));
+        }
+    }
+
+    @Override
+    public void uploadObject(String bucket, String object, InputStream stream) {
+        try {
+            Storage storage = StorageOptions.getDefaultInstance().getService();
+            BlobId blobId = BlobId.of(bucket, object);
+            BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
+            storage.create(blobInfo, IOUtils.toByteArray(stream));
+        } catch (Exception e) {
+            log.error("Cannot upload object {} to bucket {}. Reason: {}", object, bucket, e.getMessage());
+            throw new DlabException(String.format("Cannot upload object %s to bucket %s. Reason: %s", object, bucket, e.getMessage()));
+        }
+    }
+
+    @Override
+    public byte[] downloadObject(String bucket, String object) {
+        try {
+            Storage storage = StorageOptions.getDefaultInstance().getService();
+            Blob blob = storage.get(BlobId.of(bucket, object));
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            blob.downloadTo(outputStream); //todo add check for blob != null and throw exception
+            return outputStream.toByteArray();
+        } catch (Exception e) {
+            log.error("Cannot download object {} from bucket {}. Reason: {}", object, bucket, e.getMessage());
+            throw new DlabException(String.format("Cannot download object %s from bucket %s. Reason: %s", object, bucket, e.getMessage()));
+        }
+    }
+
+    @Override
+    public void deleteObject(String bucket, String object) {
+        try {
+            Storage storage = StorageOptions.getDefaultInstance().getService();
+            storage.delete(bucket, object);
+        } catch (Exception e) {
+            log.error("Cannot delete object {} from bucket {}. Reason: {}", object, bucket, e.getMessage());
+            throw new DlabException(String.format("Cannot delete object %s from bucket %s. Reason: %s", object, bucket, e.getMessage()));
+        }
+    }
+
+    private BucketDTO toBucketDTO(BlobInfo blobInfo) {
+        final String size = FileUtils.byteCountToDisplaySize(blobInfo.getSize());
+        Date date = new Date(blobInfo.getCreateTime());
+        SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss");
+        return BucketDTO.builder()
+                .bucket(blobInfo.getBucket())
+                .object(blobInfo.getName())
+                .size(size)
+                .creationDate(formatter.format(date))
+                .build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/CloudProviderModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/CloudProviderModule.java
index 7ea2739..c4c771d 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/CloudProviderModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/CloudProviderModule.java
@@ -28,6 +28,7 @@ import com.epam.dlab.backendapi.dao.azure.AzureBillingDAO;
 import com.epam.dlab.backendapi.dao.gcp.GcpBillingDao;
 import com.epam.dlab.backendapi.interceptor.BudgetLimitInterceptor;
 import com.epam.dlab.backendapi.resources.BillingResource;
+import com.epam.dlab.backendapi.resources.BucketResource;
 import com.epam.dlab.backendapi.resources.aws.ComputationalResourceAws;
 import com.epam.dlab.backendapi.resources.azure.ComputationalResourceAzure;
 import com.epam.dlab.backendapi.resources.gcp.ComputationalResourceGcp;
@@ -85,6 +86,7 @@ public class CloudProviderModule extends CloudModule {
         environment.jersey().register(injector.getInstance(ComputationalResourceAws.class));
         environment.jersey().register(injector.getInstance(ComputationalResourceAzure.class));
         environment.jersey().register(injector.getInstance(ComputationalResourceGcp.class));
+        environment.jersey().register(injector.getInstance(BucketResource.class));
         if (injector.getInstance(SelfServiceApplicationConfiguration.class).isGcpOuauth2AuthenticationEnabled()) {
             environment.jersey().register(injector.getInstance(GcpOauthResource.class));
         }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
index cf08d12..f8de46d 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
@@ -23,9 +23,66 @@ import com.epam.dlab.ModuleBase;
 import com.epam.dlab.auth.contract.SecurityAPI;
 import com.epam.dlab.backendapi.auth.SelfServiceSecurityAuthorizer;
 import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.*;
-import com.epam.dlab.backendapi.service.*;
-import com.epam.dlab.backendapi.service.impl.*;
+import com.epam.dlab.backendapi.dao.BackupDao;
+import com.epam.dlab.backendapi.dao.BackupDaoImpl;
+import com.epam.dlab.backendapi.dao.EndpointDAO;
+import com.epam.dlab.backendapi.dao.EndpointDAOImpl;
+import com.epam.dlab.backendapi.dao.ImageExploratoryDao;
+import com.epam.dlab.backendapi.dao.ImageExploratoryDaoImpl;
+import com.epam.dlab.backendapi.dao.ProjectDAO;
+import com.epam.dlab.backendapi.dao.ProjectDAOImpl;
+import com.epam.dlab.backendapi.dao.UserGroupDao;
+import com.epam.dlab.backendapi.dao.UserGroupDaoImpl;
+import com.epam.dlab.backendapi.dao.UserRoleDao;
+import com.epam.dlab.backendapi.dao.UserRoleDaoImpl;
+import com.epam.dlab.backendapi.service.AccessKeyService;
+import com.epam.dlab.backendapi.service.ApplicationSettingService;
+import com.epam.dlab.backendapi.service.ApplicationSettingServiceImpl;
+import com.epam.dlab.backendapi.service.BackupService;
+import com.epam.dlab.backendapi.service.BucketService;
+import com.epam.dlab.backendapi.service.ComputationalService;
+import com.epam.dlab.backendapi.service.EndpointService;
+import com.epam.dlab.backendapi.service.EnvironmentService;
+import com.epam.dlab.backendapi.service.ExploratoryService;
+import com.epam.dlab.backendapi.service.ExternalLibraryService;
+import com.epam.dlab.backendapi.service.GitCredentialService;
+import com.epam.dlab.backendapi.service.GuacamoleService;
+import com.epam.dlab.backendapi.service.ImageExploratoryService;
+import com.epam.dlab.backendapi.service.InactivityService;
+import com.epam.dlab.backendapi.service.KeycloakService;
+import com.epam.dlab.backendapi.service.KeycloakServiceImpl;
+import com.epam.dlab.backendapi.service.LibraryService;
+import com.epam.dlab.backendapi.service.ProjectService;
+import com.epam.dlab.backendapi.service.ReuploadKeyService;
+import com.epam.dlab.backendapi.service.SchedulerJobService;
+import com.epam.dlab.backendapi.service.SecurityService;
+import com.epam.dlab.backendapi.service.SecurityServiceImpl;
+import com.epam.dlab.backendapi.service.SystemInfoService;
+import com.epam.dlab.backendapi.service.TagService;
+import com.epam.dlab.backendapi.service.TagServiceImpl;
+import com.epam.dlab.backendapi.service.UserGroupService;
+import com.epam.dlab.backendapi.service.UserRoleService;
+import com.epam.dlab.backendapi.service.UserRoleServiceImpl;
+import com.epam.dlab.backendapi.service.UserSettingService;
+import com.epam.dlab.backendapi.service.UserSettingServiceImpl;
+import com.epam.dlab.backendapi.service.impl.AccessKeyServiceImpl;
+import com.epam.dlab.backendapi.service.impl.BackupServiceImpl;
+import com.epam.dlab.backendapi.service.impl.BucketServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ComputationalServiceImpl;
+import com.epam.dlab.backendapi.service.impl.EndpointServiceImpl;
+import com.epam.dlab.backendapi.service.impl.EnvironmentServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ExploratoryServiceImpl;
+import com.epam.dlab.backendapi.service.impl.GitCredentialServiceImpl;
+import com.epam.dlab.backendapi.service.impl.GuacamoleServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ImageExploratoryServiceImpl;
+import com.epam.dlab.backendapi.service.impl.InactivityServiceImpl;
+import com.epam.dlab.backendapi.service.impl.LibraryServiceImpl;
+import com.epam.dlab.backendapi.service.impl.MavenCentralLibraryService;
+import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ReuploadKeyServiceImpl;
+import com.epam.dlab.backendapi.service.impl.SchedulerJobServiceImpl;
+import com.epam.dlab.backendapi.service.impl.SystemInfoServiceImpl;
+import com.epam.dlab.backendapi.service.impl.UserGroupServiceImpl;
 import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.mongo.MongoService;
 import com.epam.dlab.rest.client.RESTService;
@@ -75,6 +132,9 @@ public class DevModule extends ModuleBase<SelfServiceApplicationConfiguration> i
 		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.PROVISIONING_SERVICE_NAME))
 				.toInstance(configuration.getProvisioningFactory()
 						.build(environment, ServiceConsts.PROVISIONING_SERVICE_NAME));
+		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BUCKET_SERVICE_NAME))
+				.toInstance(configuration.getBucketFactory()
+						.build(environment, ServiceConsts.BUCKET_SERVICE_NAME));
 		bind(ImageExploratoryService.class).to(ImageExploratoryServiceImpl.class);
 		bind(ImageExploratoryDao.class).to(ImageExploratoryDaoImpl.class);
 		bind(BackupService.class).to(BackupServiceImpl.class);
@@ -96,17 +156,18 @@ public class DevModule extends ModuleBase<SelfServiceApplicationConfiguration> i
 		bind(ExternalLibraryService.class).to(MavenCentralLibraryService.class);
 		bind(SystemInfoService.class).to(SystemInfoServiceImpl.class);
 		bind(UserGroupService.class).to(UserGroupServiceImpl.class);
-		bind(UserRoleService.class).to(UserRoleServiceImpl.class);
-		bind(UserRoleDao.class).to(UserRoleDaoImpl.class);
-		bind(UserGroupDao.class).to(UserGroupDaoImpl.class);
-		bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
-		bind(UserSettingService.class).to(UserSettingServiceImpl.class);
-		bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
-		bind(EndpointService.class).to(EndpointServiceImpl.class);
-		bind(EndpointDAO.class).to(EndpointDAOImpl.class);
-		bind(ProjectService.class).to(ProjectServiceImpl.class);
-		bind(ProjectDAO.class).to(ProjectDAOImpl.class);
-	}
+        bind(UserRoleService.class).to(UserRoleServiceImpl.class);
+        bind(UserRoleDao.class).to(UserRoleDaoImpl.class);
+        bind(UserGroupDao.class).to(UserGroupDaoImpl.class);
+        bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
+        bind(UserSettingService.class).to(UserSettingServiceImpl.class);
+        bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
+        bind(EndpointService.class).to(EndpointServiceImpl.class);
+        bind(EndpointDAO.class).to(EndpointDAOImpl.class);
+        bind(ProjectService.class).to(ProjectServiceImpl.class);
+        bind(ProjectDAO.class).to(ProjectDAOImpl.class);
+        bind(BucketService.class).to(BucketServiceImpl.class);
+    }
 
 	private void configureCors(Environment environment) {
 		final FilterRegistration.Dynamic cors =
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
index 0d0ae1d..6896ee7 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
@@ -20,11 +20,68 @@
 package com.epam.dlab.backendapi.modules;
 
 import com.epam.dlab.ModuleBase;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
 import com.epam.dlab.backendapi.auth.SelfServiceSecurityAuthorizer;
-import com.epam.dlab.backendapi.dao.*;
-import com.epam.dlab.backendapi.service.*;
-import com.epam.dlab.backendapi.service.impl.*;
+import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.dlab.backendapi.dao.BackupDao;
+import com.epam.dlab.backendapi.dao.BackupDaoImpl;
+import com.epam.dlab.backendapi.dao.EndpointDAO;
+import com.epam.dlab.backendapi.dao.EndpointDAOImpl;
+import com.epam.dlab.backendapi.dao.ImageExploratoryDao;
+import com.epam.dlab.backendapi.dao.ImageExploratoryDaoImpl;
+import com.epam.dlab.backendapi.dao.ProjectDAO;
+import com.epam.dlab.backendapi.dao.ProjectDAOImpl;
+import com.epam.dlab.backendapi.dao.UserGroupDao;
+import com.epam.dlab.backendapi.dao.UserGroupDaoImpl;
+import com.epam.dlab.backendapi.dao.UserRoleDao;
+import com.epam.dlab.backendapi.dao.UserRoleDaoImpl;
+import com.epam.dlab.backendapi.service.AccessKeyService;
+import com.epam.dlab.backendapi.service.ApplicationSettingService;
+import com.epam.dlab.backendapi.service.ApplicationSettingServiceImpl;
+import com.epam.dlab.backendapi.service.BackupService;
+import com.epam.dlab.backendapi.service.BucketService;
+import com.epam.dlab.backendapi.service.ComputationalService;
+import com.epam.dlab.backendapi.service.EndpointService;
+import com.epam.dlab.backendapi.service.EnvironmentService;
+import com.epam.dlab.backendapi.service.ExploratoryService;
+import com.epam.dlab.backendapi.service.ExternalLibraryService;
+import com.epam.dlab.backendapi.service.GitCredentialService;
+import com.epam.dlab.backendapi.service.GuacamoleService;
+import com.epam.dlab.backendapi.service.ImageExploratoryService;
+import com.epam.dlab.backendapi.service.InactivityService;
+import com.epam.dlab.backendapi.service.KeycloakService;
+import com.epam.dlab.backendapi.service.KeycloakServiceImpl;
+import com.epam.dlab.backendapi.service.LibraryService;
+import com.epam.dlab.backendapi.service.ProjectService;
+import com.epam.dlab.backendapi.service.ReuploadKeyService;
+import com.epam.dlab.backendapi.service.SchedulerJobService;
+import com.epam.dlab.backendapi.service.SecurityService;
+import com.epam.dlab.backendapi.service.SecurityServiceImpl;
+import com.epam.dlab.backendapi.service.SystemInfoService;
+import com.epam.dlab.backendapi.service.TagService;
+import com.epam.dlab.backendapi.service.TagServiceImpl;
+import com.epam.dlab.backendapi.service.UserGroupService;
+import com.epam.dlab.backendapi.service.UserRoleService;
+import com.epam.dlab.backendapi.service.UserRoleServiceImpl;
+import com.epam.dlab.backendapi.service.UserSettingService;
+import com.epam.dlab.backendapi.service.UserSettingServiceImpl;
+import com.epam.dlab.backendapi.service.impl.AccessKeyServiceImpl;
+import com.epam.dlab.backendapi.service.impl.BackupServiceImpl;
+import com.epam.dlab.backendapi.service.impl.BucketServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ComputationalServiceImpl;
+import com.epam.dlab.backendapi.service.impl.EndpointServiceImpl;
+import com.epam.dlab.backendapi.service.impl.EnvironmentServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ExploratoryServiceImpl;
+import com.epam.dlab.backendapi.service.impl.GitCredentialServiceImpl;
+import com.epam.dlab.backendapi.service.impl.GuacamoleServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ImageExploratoryServiceImpl;
+import com.epam.dlab.backendapi.service.impl.InactivityServiceImpl;
+import com.epam.dlab.backendapi.service.impl.LibraryServiceImpl;
+import com.epam.dlab.backendapi.service.impl.MavenCentralLibraryService;
+import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ReuploadKeyServiceImpl;
+import com.epam.dlab.backendapi.service.impl.SchedulerJobServiceImpl;
+import com.epam.dlab.backendapi.service.impl.SystemInfoServiceImpl;
+import com.epam.dlab.backendapi.service.impl.UserGroupServiceImpl;
 import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.mongo.MongoService;
 import com.epam.dlab.rest.client.RESTService;
@@ -66,6 +123,9 @@ public class ProductionModule extends ModuleBase<SelfServiceApplicationConfigura
 		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.PROVISIONING_SERVICE_NAME))
 				.toInstance(configuration.getProvisioningFactory().build(environment, ServiceConsts
 						.PROVISIONING_SERVICE_NAME));
+		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BUCKET_SERVICE_NAME))
+				.toInstance(configuration.getBucketFactory().build(environment, ServiceConsts
+						.BUCKET_SERVICE_NAME));
 		bind(ImageExploratoryService.class).to(ImageExploratoryServiceImpl.class);
 		bind(ImageExploratoryDao.class).to(ImageExploratoryDaoImpl.class);
 		bind(BackupService.class).to(BackupServiceImpl.class);
@@ -88,16 +148,17 @@ public class ProductionModule extends ModuleBase<SelfServiceApplicationConfigura
 		bind(UserRoleDao.class).to(UserRoleDaoImpl.class);
 		bind(UserGroupDao.class).to(UserGroupDaoImpl.class);
 		bind(InactivityService.class).to(InactivityServiceImpl.class);
-		bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
-		bind(UserSettingService.class).to(UserSettingServiceImpl.class);
-		bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
-		bind(EndpointService.class).to(EndpointServiceImpl.class);
-		bind(EndpointDAO.class).to(EndpointDAOImpl.class);
-		bind(ProjectService.class).to(ProjectServiceImpl.class);
-		bind(ProjectDAO.class).to(ProjectDAOImpl.class);
-		bind(TagService.class).to(TagServiceImpl.class);
-		bind(SecurityService.class).to(SecurityServiceImpl.class);
-		bind(KeycloakService.class).to(KeycloakServiceImpl.class);
-		bind(Client.class).toInstance(httpClient);
-	}
+        bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
+        bind(UserSettingService.class).to(UserSettingServiceImpl.class);
+        bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
+        bind(EndpointService.class).to(EndpointServiceImpl.class);
+        bind(EndpointDAO.class).to(EndpointDAOImpl.class);
+        bind(ProjectService.class).to(ProjectServiceImpl.class);
+        bind(ProjectDAO.class).to(ProjectDAOImpl.class);
+        bind(TagService.class).to(TagServiceImpl.class);
+        bind(SecurityService.class).to(SecurityServiceImpl.class);
+        bind(KeycloakService.class).to(KeycloakServiceImpl.class);
+        bind(BucketService.class).to(BucketServiceImpl.class);
+        bind(Client.class).toInstance(httpClient);
+    }
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java
new file mode 100644
index 0000000..a98daa2
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.resources;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.service.BucketService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+import java.nio.file.Paths;
+
+@Path("/bucket")
+@Slf4j
+public class BucketResource {
+    private final BucketService bucketService;
+
+    @Inject
+    public BucketResource(BucketService bucketService) {
+        this.bucketService = bucketService;
+    }
+
+    @GET
+    @Path("/{bucket}/endpoint/{endpoint}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getListOfObjects(@Auth UserInfo userInfo,
+                                     @PathParam("bucket") String bucket,
+                                     @PathParam("endpoint") String endpoint) {
+        return Response.ok(bucketService.getObjects(userInfo, bucket, endpoint)).build();
+    }
+
+    @POST
+    @Path("/upload")
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response uploadObject(@Auth UserInfo userInfo,
+                                 @FormDataParam("object") String object,
+                                 @FormDataParam("bucket") String bucket,
+                                 @FormDataParam("endpoint") String endpoint,
+                                 @FormDataParam("file") InputStream fileInputStream,
+                                 @FormDataParam("file") FormDataContentDisposition fileMetaData) {
+        bucketService.uploadObjects(userInfo, bucket, object, endpoint, fileInputStream);
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/{bucket}/object/{object}/endpoint/{endpoint}/download")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_OCTET_STREAM)
+    public Response downloadObject(@Auth UserInfo userInfo,
+                                   @PathParam("bucket") String bucket,
+                                   @PathParam("object") String object,
+                                   @PathParam("endpoint") String endpoint) {
+        return Response.ok(bucketService.downloadObject(userInfo, bucket, object, endpoint))
+                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + Paths.get(object).getFileName() + "\"")
+                .build();
+    }
+
+    @DELETE
+    @Path("/{bucket}/object/{object}/endpoint/{endpoint}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response deleteObject(@Auth UserInfo userInfo,
+                                 @PathParam("bucket") String bucket,
+                                 @PathParam("object") String object,
+                                 @PathParam("endpoint") String endpoint) {
+        bucketService.deleteObject(userInfo, bucket, object, endpoint);
+        return Response.ok().build();
+    }
+}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BucketDownloadDTO.java
similarity index 61%
copy from services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
copy to services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BucketDownloadDTO.java
index d376665..eb26202 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BucketDownloadDTO.java
@@ -17,16 +17,19 @@
  * under the License.
  */
 
-package com.epam.dlab.constants;
+package com.epam.dlab.backendapi.resources.dto;
 
-public final class ServiceConsts {
-	public static final String MONGO_NAME = "mongo";
-	public static final String PROVISIONING_SERVICE_NAME = "provisioningService";
-	public static final String MAVEN_SEARCH_API = "mavenSearchService";
-	public static final String SECURITY_SERVICE_NAME = "securityService";
-	public static final String SELF_SERVICE_NAME = "selfService";
-	public static final String PROVISIONING_USER_AGENT = "provisioning-service";
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
 
-	private ServiceConsts() {
-	}
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BucketDownloadDTO {
+    @NotBlank(message = "field cannot be empty")
+    private final String bucket;
+    @NotBlank(message = "field cannot be empty")
+    private final String object;
+    @NotBlank(message = "field cannot be empty")
+    private final String endpoint;
 }
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
similarity index 57%
copy from services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
copy to services/self-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
index d376665..0377969 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
@@ -17,16 +17,20 @@
  * under the License.
  */
 
-package com.epam.dlab.constants;
+package com.epam.dlab.backendapi.service;
 
-public final class ServiceConsts {
-	public static final String MONGO_NAME = "mongo";
-	public static final String PROVISIONING_SERVICE_NAME = "provisioningService";
-	public static final String MAVEN_SEARCH_API = "mavenSearchService";
-	public static final String SECURITY_SERVICE_NAME = "securityService";
-	public static final String SELF_SERVICE_NAME = "selfService";
-	public static final String PROVISIONING_USER_AGENT = "provisioning-service";
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.dto.bucket.BucketDTO;
 
-	private ServiceConsts() {
-	}
+import java.io.InputStream;
+import java.util.List;
+
+public interface BucketService {
+    List<BucketDTO> getObjects(UserInfo userInfo, String bucket, String endpoint);
+
+    void uploadObjects(UserInfo userInfo, String bucket, String object, String endpoint, InputStream inputStream);
+
+    byte[] downloadObject(UserInfo userInfo, String bucket, String object, String endpoint);
+
+    void deleteObject(UserInfo userInfo, String bucket, String object, String endpoint);
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BucketServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BucketServiceImpl.java
new file mode 100644
index 0000000..ce72a6f
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BucketServiceImpl.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.service.impl;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.domain.EndpointDTO;
+import com.epam.dlab.backendapi.service.BucketService;
+import com.epam.dlab.backendapi.service.EndpointService;
+import com.epam.dlab.constants.ServiceConsts;
+import com.epam.dlab.dto.bucket.BucketDTO;
+import com.epam.dlab.exceptions.DlabException;
+import com.epam.dlab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpStatus;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
+
+@Slf4j
+public class BucketServiceImpl implements BucketService {
+    private static final String BUCKET_GET_OBJECTS = "%sbucket/%s";
+    private static final String BUCKET_UPLOAD_OBJECT = "%sbucket/upload";
+    private static final String BUCKET_DOWNLOAD_OBJECT = "%sbucket/%s/object/%s/download";
+    private static final String BUCKET_DELETE_OBJECT = "%sbucket/%s/object/%s";
+
+    private final EndpointService endpointService;
+    private final RESTService provisioningService;
+
+    @Inject
+    public BucketServiceImpl(EndpointService endpointService, @Named(ServiceConsts.BUCKET_SERVICE_NAME) RESTService provisioningService) {
+        this.endpointService = endpointService;
+        this.provisioningService = provisioningService;
+    }
+
+    @Override
+    public List<BucketDTO> getObjects(UserInfo userInfo, String bucket, String endpoint) {
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            return provisioningService.get(String.format(BUCKET_GET_OBJECTS, endpointDTO.getUrl(), bucket), userInfo.getAccessToken(), new GenericType<List<BucketDTO>>() {
+            });
+        } catch (Exception e) {
+            log.error("Cannot get objects from bucket {} for user {}, endpoint {}. Reason {}", bucket, userInfo.getName(), endpoint, e.getMessage());
+            throw new DlabException(String.format("Cannot get objects from bucket %s for user %s, endpoint %s. Reason %s", bucket, userInfo.getName(), endpoint, e.getMessage()));
+        }
+    }
+
+    @Override
+    public void uploadObjects(UserInfo userInfo, String bucket, String object, String endpoint, InputStream inputStream) {
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            FormDataMultiPart formData = getFormDataMultiPart(bucket, object, inputStream);
+            Response response = provisioningService.postForm(String.format(BUCKET_UPLOAD_OBJECT, endpointDTO.getUrl()), userInfo.getAccessToken(), formData, Response.class);
+            if (response.getStatus() != HttpStatus.SC_OK) {
+                throw new DlabException(String.format("Something went wrong. Response status is %s ", response.getStatus()));
+            }
+        } catch (Exception e) {
+            log.error("Cannot upload object {} to bucket {} for user {}, endpoint {}. Reason {}", object, bucket, userInfo.getName(), endpoint, e.getMessage());
+            throw new DlabException(String.format("Cannot upload object %s to bucket %s for user %s, endpoint %s. Reason %s", object, bucket, userInfo.getName(), endpoint, e.getMessage()));
+        }
+    }
+
+    @Override
+    public byte[] downloadObject(UserInfo userInfo, String bucket, String object, String endpoint) {
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            return provisioningService.getWithMediaTypes(String.format(BUCKET_DOWNLOAD_OBJECT, endpointDTO.getUrl(), bucket, encodeObject(object)), userInfo.getAccessToken(), byte[].class,
+                    APPLICATION_JSON, APPLICATION_OCTET_STREAM);
+        } catch (Exception e) {
+            log.error("Cannot upload object {} from bucket {} for user {}, endpoint {}. Reason {}", object, bucket, userInfo.getName(), endpoint, e.getMessage());
+            throw new DlabException(String.format("Cannot download object %s from bucket %s for user %s, endpoint %s. Reason %s", object, bucket, userInfo.getName(), endpoint, e.getMessage()));
+        }
+    }
+
+    @Override
+    public void deleteObject(UserInfo userInfo, String bucket, String object, String endpoint) {
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            Response response = provisioningService.delete(String.format(BUCKET_DELETE_OBJECT, endpointDTO.getUrl(), bucket, encodeObject(object)), userInfo.getAccessToken(), Response.class,
+                    APPLICATION_JSON, APPLICATION_JSON);
+            if (response.getStatus() != HttpStatus.SC_OK) {
+                throw new DlabException(String.format("Something went wrong. Response status is %s ", response.getStatus()));
+            }
+        } catch (Exception e) {
+            log.error("Cannot delete object {} from bucket {} for user {}, endpoint {}. Reason {}", object, bucket, userInfo.getName(), endpoint, e.getMessage());
+            throw new DlabException(String.format("Cannot delete object %s from bucket %s for user %s, endpoint %s. Reason %s", object, bucket, userInfo.getName(), endpoint, e.getMessage()));
+        }
+    }
+
+    private String encodeObject(String object) throws UnsupportedEncodingException {
+        return URLEncoder.encode(object, StandardCharsets.UTF_8.toString());
+    }
+
+    private FormDataMultiPart getFormDataMultiPart(String bucket, String object, InputStream inputStream) {
+        FormDataMultiPart formData = new FormDataMultiPart();
+        formData.field("file", inputStream, MediaType.valueOf(APPLICATION_OCTET_STREAM));
+        formData.field("bucket", bucket);
+        formData.field("object", object);
+        return formData;
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
index e53b78c..97079e3 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
@@ -41,11 +41,23 @@ import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 
 import java.lang.reflect.Field;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class InfrastructureTemplateServiceBaseTest {
@@ -89,7 +101,7 @@ public class InfrastructureTemplateServiceBaseTest {
 		emDto2.setExploratoryEnvironmentShapes(shapes2);
 		List<ExploratoryMetadataDTO> expectedEmdDtoList = Arrays.asList(emDto1, emDto2);
 		when(userGroupDao.getUserGroups(anyString())).thenReturn(Collections.emptySet());
-		when(provisioningService.get(anyString(), anyString(), any())).thenReturn(expectedEmdDtoList.toArray());
+		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(expectedEmdDtoList.toArray());
 		when(settingsDAO.getConfOsFamily()).thenReturn("someConfOsFamily");
 
 		UserInfo userInfo = new UserInfo("test", "token");
@@ -108,7 +120,7 @@ public class InfrastructureTemplateServiceBaseTest {
 	public void getExploratoryTemplatesWithException() {
 		when(endpointService.get(anyString())).thenReturn(endpointDTO());
 		doThrow(new DlabException("Could not load list of exploratory templates for user"))
-				.when(provisioningService).get(anyString(), anyString(), any());
+				.when(provisioningService).get(anyString(), anyString(), any(Class.class));
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		try {
@@ -131,7 +143,7 @@ public class InfrastructureTemplateServiceBaseTest {
 		);
 		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
 				null, null, null, null, true)));
-		when(provisioningService.get(anyString(), anyString(), any())).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
+		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
 
 		List<FullComputationalTemplate> expectedFullCmdDtoList = expectedCmdDtoList.stream()
 				.map(e -> infrastructureTemplateServiceBaseChild.getCloudFullComputationalTemplate(e))
@@ -154,7 +166,7 @@ public class InfrastructureTemplateServiceBaseTest {
 	public void getComputationalTemplatesWhenMethodThrowsException() {
 		when(endpointService.get(anyString())).thenReturn(endpointDTO());
 		doThrow(new DlabException("Could not load list of computational templates for user"))
-				.when(provisioningService).get(anyString(), anyString(), any());
+				.when(provisioningService).get(anyString(), anyString(), any(Class.class));
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		try {
@@ -173,7 +185,7 @@ public class InfrastructureTemplateServiceBaseTest {
 		final ComputationalMetadataDTO computationalMetadataDTO = new ComputationalMetadataDTO("dataengine-service");
 		computationalMetadataDTO.setComputationResourceShapes(Collections.emptyMap());
 		List<ComputationalMetadataDTO> expectedCmdDtoList = Collections.singletonList(computationalMetadataDTO);
-		when(provisioningService.get(anyString(), anyString(), any())).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
+		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
 		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
 				null, null, null, null, true)));
 		when(configuration.getMinEmrInstanceCount()).thenReturn(1);


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@dlab.apache.org
For additional commands, e-mail: commits-help@dlab.apache.org