Skip to content

Commit

Permalink
Feature mgmt client (#5)
Browse files Browse the repository at this point in the history
* Added TenantMgmtClient and SystemMgmtClient - initial methods:
    * listRmgs
    * listSubtenants
    * getSubtenantDetails
    * listRmgNodes
    * getTenantInfo
    * listPolicies
    * listUids
    * getSharedSecret
  • Loading branch information
twincitiesguy authored Apr 16, 2019
1 parent 10b4df2 commit 2ae13d5
Show file tree
Hide file tree
Showing 73 changed files with 3,638 additions and 193 deletions.
19 changes: 10 additions & 9 deletions readme.tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,21 @@ atmos.secret - Shared secret key for the uid
atmos.endpoints - Comma separated list of endpoint URIs (more than one is optional)

ACDP:
acdp.admin.endpoint - ACDP admin endpoint, usually http://admin_node:8080/
acdp.admin.endpoint - ACDP admin endpoint, usually http://admin_node:8080
acdp.admin.username - ACDP administrator username
acdp.admin.password - ACDP administrator password
acdp.mgmt.endpoint - ACDP management endpoint, usually http://portal_node:8080/
acdp.mgmt.endpoint - ACDP management endpoint, usually http://portal_node:8080
acdp.mgmt.username - ACDP management user (account user)
acdp.mgmt.password - ACDP management password

Atmos System Management:
atmos.sysmgmt.proto - System management protocol (usually https)
atmos.sysmgmt.host - System management host (primary or secondary node in RMG)
atmos.sysmgmt.port - System management port (usually 443)
atmos.sysmgmt.username - System management user
atmos.sysmgmt.password - System management password

Atmos Management API:
atmos.mgmt.endpoints - Management REST API endpoints, usually https://<primary-or-secondary-node>:443 (multiple optional)
atmos.mgmt.sysadmin.user - System admin user
atmos.mgmt.sysadmin.password - System admin password
atmos.mgmt.tenant - Existing tenant for testing
atmos.mgmt.tenantadmin.user - Tenant admin user
atmos.mgmt.tenantadmin.password - Tenant admin password

If a particular configuration key is missing, that test group will be skipped.


Expand Down
31 changes: 21 additions & 10 deletions src/main/java/com/emc/atmos/AbstractConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,30 +50,41 @@ public AbstractConfig( String context, URI... endpoints ) {
this.endpoints = endpoints;
}

/**
* @deprecated Please use {@link #resolveHostAndPath(String, String)} instead
*/
public URI resolvePath( String relativePath, String query ) {
return resolveHostAndPath(relativePath, query);
}

/**
* Resolves a path relative to the API context. The returned URI will be of the format
* scheme://host[:port]/context/relativePath?query. The scheme, host and port (endpoint) to use is delegated to the
* configured loadBalancingAlgorithm to balance load across multiple endpoints.
*/
public URI resolvePath( String relativePath, String query ) {
public URI resolveHostAndPath(String relativePath, String query) {
String path = relativePath;

// make sure we have a root path
if ( path.length() == 0 || path.charAt( 0 ) != '/' ) path = '/' + path;
if (path.length() == 0 || path.charAt(0) != '/') path = '/' + path;

// don't add the context if it's already there
if ( !path.startsWith( context ) ) path = context + path;
if (!path.startsWith(context)) path = context + path;

return resolveHost(path, query);
}

URI endpoint = loadBalancingAlgorithm.getNextEndpoint( endpoints );
public URI resolveHost(String absolutePath, String query) {
URI endpoint = loadBalancingAlgorithm.getNextEndpoint(endpoints);

try {
URI uri = new URI( endpoint.getScheme(), null, endpoint.getHost(), endpoint.getPort(),
path, query, null );
l4j.debug( "raw path & query: " + path + "?" + query );
l4j.debug( "encoded URI: " + uri );
URI uri = new URI(endpoint.getScheme(), null, endpoint.getHost(), endpoint.getPort(),
absolutePath, query, null);
l4j.debug("raw path & query: " + absolutePath + "?" + query);
l4j.debug("encoded URI: " + uri);
return uri;
} catch ( URISyntaxException e ) {
throw new RuntimeException( "Invalid URI syntax", e );
} catch (URISyntaxException e) {
throw new RuntimeException("Invalid URI syntax", e);
}
}

Expand Down
93 changes: 93 additions & 0 deletions src/main/java/com/emc/atmos/AbstractJerseyClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* BSD 3-Clause License
*
* Copyright (c) 2013-2018, Dell EMC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package com.emc.atmos;

import com.emc.util.BasicResponse;
import com.emc.util.HttpUtil;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;

public abstract class AbstractJerseyClient<C extends AbstractConfig> {
protected C config;
protected Client client;

public AbstractJerseyClient(C config) {
this.config = config;
this.client = createClient(config);
}

protected abstract Client createClient(C config);

/**
* Populates a response object with data from the ClientResponse.
*/
protected <T extends BasicResponse> T fillResponse(T response, ClientResponse clientResponse) {
Response.StatusType statusType = clientResponse.getStatusInfo();
MediaType type = clientResponse.getType();
URI location = clientResponse.getLocation();
response.setHttpStatus(clientResponse.getStatus());
response.setHttpMessage(statusType == null ? null : statusType.getReasonPhrase());
response.setHeaders(clientResponse.getHeaders());
response.setContentType(type == null ? null : type.toString());
response.setContentLength(clientResponse.getLength());
response.setLocation(location == null ? null : location.toString());
if (clientResponse.getHeaders() != null) {
// workaround for Github Issue #3
response.setDate(HttpUtil.safeHeaderParse(clientResponse.getHeaders().getFirst(HttpUtil.HEADER_DATE)));
response.setLastModified(HttpUtil.safeHeaderParse(clientResponse.getHeaders().getFirst(HttpUtil.HEADER_LAST_MODIFIED)));
response.setETag(clientResponse.getHeaders().getFirst(HttpUtil.HEADER_ETAG));
}
return response;
}

protected <R extends BasicResponse> R executeAndClose(WebResource.Builder builder, Class<R> responseType) {
ClientResponse response = builder.get(ClientResponse.class);

R ret = response.getEntity(responseType);

response.close();

return fillResponse(ret, response);
}

protected WebResource.Builder buildRequest(String pathWithinContext, String query) {
URI uri = config.resolveHostAndPath(pathWithinContext, query);

return client.resource(uri).getRequestBuilder();
}
}
11 changes: 5 additions & 6 deletions src/main/java/com/emc/atmos/api/AbstractAtmosApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
*/
package com.emc.atmos.api;

import com.emc.atmos.AbstractJerseyClient;
import com.emc.atmos.api.bean.GetAccessTokenResponse;
import com.emc.atmos.api.request.*;
import com.emc.util.HttpUtil;
Expand All @@ -39,13 +40,11 @@
import java.util.List;
import java.util.Map;

public abstract class AbstractAtmosApi implements AtmosApi {
public abstract class AbstractAtmosApi extends AbstractJerseyClient<AtmosConfig> implements AtmosApi {
public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";

protected AtmosConfig config;

public AbstractAtmosApi( AtmosConfig config ) {
this.config = config;
super( config );
}

@Override
Expand Down Expand Up @@ -91,7 +90,7 @@ public URL getShareableUrl( ObjectIdentifier identifier, Date expirationDate, St
if ( identifier instanceof ObjectKey )
throw new IllegalArgumentException( "You cannot create shareable URLs using a key; try using the object ID" );

URI uri = config.resolvePath( identifier.getRelativeResourcePath(), null );
URI uri = config.resolveHostAndPath( identifier.getRelativeResourcePath(), null );
String path = uri.getPath().toLowerCase();
long expiresTime = expirationDate.getTime() / 1000;

Expand Down Expand Up @@ -125,7 +124,7 @@ public void deleteAccessToken( URL url ) {

@Override
public PreSignedRequest preSignRequest( Request request, Date expiration ) throws MalformedURLException {
URI uri = config.resolvePath( request.getServiceRelativePath(), request.getQuery() );
URI uri = config.resolveHostAndPath( request.getServiceRelativePath(), request.getQuery() );
Map<String, List<Object>> headers = request.generateHeaders( config.isEncodeUtf8() );

String contentType = null;
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/emc/atmos/api/AtmosApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import com.emc.atmos.api.bean.*;
import com.emc.atmos.api.request.*;
import com.emc.util.BasicResponse;

import java.io.IOException;
import java.io.InputStream;
Expand Down
18 changes: 7 additions & 11 deletions src/main/java/com/emc/atmos/api/RestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,10 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* @see HttpUtil
*/
public final class RestUtil {
public static final String HEADER_CONTENT_TYPE = "Content-Type";
public static final String HEADER_DATE = "Date";
public static final String HEADER_EXPECT = "Expect";
public static final String HEADER_RANGE = "Range";
public static final String HEADER_ETAG = "ETag";
public static final String HEADER_LAST_MODIFIED = "Last-Modified";

public static final String XHEADER_CONTENT_CHECKSUM = "x-emc-content-checksum";
public static final String XHEADER_DATE = "x-emc-date";
public static final String XHEADER_EXPIRES = "x-emc-expires";
Expand Down Expand Up @@ -143,7 +139,7 @@ public static void signRequest( String method, String path, String query, Map<St

// Add date header
Date serverTime = new Date( System.currentTimeMillis() - serverClockSkew );
headers.put( HEADER_DATE, Arrays.asList( (Object) HttpUtil.headerFormat( serverTime ) ) );
headers.put( HttpUtil.HEADER_DATE, Arrays.asList( (Object) HttpUtil.headerFormat( serverTime ) ) );
headers.put( XHEADER_DATE, Arrays.asList( (Object) HttpUtil.headerFormat( serverTime ) ) );

// Add uid to headers
Expand All @@ -156,9 +152,9 @@ public static void signRequest( String method, String path, String query, Map<St
builder.append( method ).append( "\n" );

// Add the following header values or blank lines if they aren't present
builder.append( generateHashLine( headers, HEADER_CONTENT_TYPE ) );
builder.append( generateHashLine( headers, HEADER_RANGE ) );
builder.append( generateHashLine( headers, HEADER_DATE ) );
builder.append( generateHashLine( headers, HttpUtil.HEADER_CONTENT_TYPE ) );
builder.append( generateHashLine( headers, HttpUtil.HEADER_RANGE ) );
builder.append( generateHashLine( headers, HttpUtil.HEADER_DATE ) );

// Add the resource
builder.append( path.toLowerCase() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
*/
package com.emc.atmos.api.bean;

import com.emc.util.BasicResponse;

import java.net.URL;

public class CreateAccessTokenResponse extends BasicResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.emc.atmos.api.ChecksumValueImpl;
import com.emc.atmos.api.ObjectId;
import com.emc.atmos.api.RestUtil;
import com.emc.util.BasicResponse;

public class CreateObjectResponse extends BasicResponse {
public ObjectId getObjectId() {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/emc/atmos/api/bean/GenericResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
*/
package com.emc.atmos.api.bean;

import com.emc.util.BasicResponse;

public class GenericResponse<T> extends BasicResponse {
T content;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import com.emc.atmos.api.Acl;
import com.emc.atmos.api.RestUtil;
import com.emc.util.BasicResponse;

public class GetAccessTokenResponse extends BasicResponse {
AccessToken token;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
*/
package com.emc.atmos.api.bean;

import com.emc.util.BasicResponse;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
*/
package com.emc.atmos.api.bean;

import com.emc.util.BasicResponse;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/emc/atmos/api/bean/ListObjectsResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
*/
package com.emc.atmos.api.bean;

import com.emc.util.BasicResponse;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
package com.emc.atmos.api.bean;

import com.emc.atmos.api.ObjectId;
import com.emc.util.BasicResponse;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.emc.atmos.api.ChecksumValue;
import com.emc.atmos.api.ChecksumValueImpl;
import com.emc.atmos.api.RestUtil;
import com.emc.util.BasicResponse;

import java.util.Map;
import java.util.TreeMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.emc.atmos.api.*;
import com.emc.atmos.api.bean.*;
import com.emc.atmos.api.request.*;
import com.emc.util.BasicResponse;
import com.emc.vipr.transform.*;
import com.emc.vipr.transform.encryption.DoesNotNeedRekeyException;
import com.emc.vipr.transform.encryption.EncryptionTransformFactory;
Expand Down
Loading

0 comments on commit 2ae13d5

Please sign in to comment.