1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-21 14:50:08 +03:00

Java OCA: New ACL classes, and tests. TODO: Create a new Exception for rule parsing errors

This commit is contained in:
Carlos Martín 2011-07-07 19:22:30 +02:00
parent 7b19d4a866
commit ec48ba7081
5 changed files with 705 additions and 0 deletions

View File

@ -0,0 +1,355 @@
/*******************************************************************************
* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)
*
* Licensed 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 org.opennebula.client.acl;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.opennebula.client.Client;
import org.opennebula.client.OneResponse;
import org.opennebula.client.PoolElement;
import org.w3c.dom.Node;
/**
* This class represents an OpenNebula ACL rule.
* It also offers static XML-RPC call wrappers.
* <br/>
* There is not a public constructor, because the information for an individual
* ACL rule cannot be retrieved from OpenNebula.
* <br/>
* Instead, Acl objects should be obtained using AclPool.getById, after the
* info method has been called.
*
* @see AclPool#getById
*/
public class Acl extends PoolElement{
private static final String METHOD_PREFIX = "acl.";
private static final String ADDRULE = METHOD_PREFIX + "addrule";
private static final String DELRULE = METHOD_PREFIX + "delrule";
private static final Map<String, Long> USERS;
private static final Map<String, Long> RESOURCES;
private static final Map<String, Long> RIGHTS;
static {
HashMap<String, Long> tmpUsers = new HashMap<String, Long>();
tmpUsers.put("#", 0x0000000100000000L);
tmpUsers.put("@", 0x0000000200000000L);
tmpUsers.put("*", 0x0000000400000000L);
USERS = Collections.unmodifiableMap(tmpUsers);
HashMap<String, Long> tmpResources = new HashMap<String, Long>();
tmpResources.put("VM" , 0x0000001000000000L);
tmpResources.put("HOST" , 0x0000002000000000L);
tmpResources.put("NET" , 0x0000004000000000L);
tmpResources.put("IMAGE" , 0x0000008000000000L);
tmpResources.put("USER" , 0x0000010000000000L);
tmpResources.put("TEMPLATE" , 0x0000020000000000L);
tmpResources.put("GROUP" , 0x0000040000000000L);
RESOURCES = Collections.unmodifiableMap(tmpResources);
HashMap<String, Long> tmpRights = new HashMap<String, Long>();
tmpRights.put("CREATE" , 0x1L);
tmpRights.put("DELETE" , 0x2L);
tmpRights.put("USE" , 0x4L);
tmpRights.put("MANAGE" , 0x8L);
tmpRights.put("INFO" , 0x10L);
tmpRights.put("INFO_POOL" , 0x20L);
tmpRights.put("INFO_POOL_MINE", 0x40L);
tmpRights.put("INSTANTIATE" , 0x80L);
tmpRights.put("CHOWN" , 0x100L);
RIGHTS = Collections.unmodifiableMap(tmpRights);
}
/**
* @see PoolElement
*/
protected Acl(Node xmlElement, Client client)
{
super(xmlElement, client);
}
// =================================
// Static XML-RPC methods
// =================================
/**
* Allocates a new ACl rule in OpenNebula
*
* @param client XML-RPC Client.
* @param user A string containing a hex number, e.g. 0x100000001
* @param resource A string containing a hex number, e.g. 0x2100000001
* @param rights A string containing a hex number, e.g. 0x10
* @return If successful the message contains the associated
* id generated for this rule.
*/
public static OneResponse allocate(Client client, String user,
String resource, String rights)
{
return client.call(ADDRULE, user, resource, rights);
}
/**
* Allocates a new ACl rule in OpenNebula
*
* @param client XML-RPC Client.
* @param user 64b encoded user
* @param resource 64b encoded user
* @param rights 64b encoded user
* @return If successful the message contains the associated
* id generated for this rule.
*/
public static OneResponse allocate(Client client, long user, long resource,
long rights)
{
return allocate(client,
Long.toHexString(user),
Long.toHexString(resource),
Long.toHexString(rights));
}
/**
* Allocates a new ACl rule in OpenNebula
*
* @param client XML-RPC Client.
* @param rule a rule string, e.g. "#5 HOST+VM/@12 INFO+CREATE+DELETE"
* @return If successful the message contains the associated
* id generated for this rule.
*/
public static OneResponse allocate(Client client, String rule)
{
String[] components = parseRule(rule);
return allocate(client, components[0], components[1], components[2]);
}
/**
* Deletes an ACL rule from OpenNebula.
*
* @param client XML-RPC Client.
* @param id The ACL rule id.
* @return A encapsulated response.
*/
public static OneResponse delete(Client client, int id)
{
return client.call(DELRULE, id);
}
// =================================
// Instanced object XML-RPC methods
// =================================
/**
* Deletes the ACL rule from OpenNebula.
*
* @see Acl#delete(Client, int)
*/
public OneResponse delete()
{
return delete(client, id);
}
// =================================
// Helpers
// =================================
public long user()
{
long ret = 0;
try
{
ret = Long.parseLong( xpath("USER"), 16 );
}
catch (NumberFormatException e)
{}
return ret;
}
public long resource()
{
long ret = 0;
try
{
ret = Long.parseLong( xpath("RESOURCE"), 16 );
}
catch (NumberFormatException e)
{}
return ret;
}
public long rights()
{
long ret = 0;
try
{
ret = Long.parseLong( xpath("RIGHTS"), 16 );
}
catch (NumberFormatException e)
{}
return ret;
}
public String toString()
{
String st = xpath("STRING");
if( st == null )
{
st = "";
}
return st;
}
// =================================
// Rule parsing
// =================================
/**
* Parses a rule string, e.g. "#5 HOST+VM/@12 INFO+CREATE+DELETE"
*
* @param rule an ACL rule in string format
* @return an Array containing 3 Strings (hex 64b numbers)
*/
public static String[] parseRule(String rule)
{
String [] ret = new String[3];
String [] components = rule.split(" ");
if( components.length != 3 )
{
// TODO: throw "String needs three components: User, Resource, Rights"
return ret;
}
ret[0] = parseUsers(components[0]);
ret[1] = parseResources(components[1]);
ret[2] = parseRights(components[2]);
return ret;
}
/**
* Converts a string in the form [#<id>, @<id>, *] to a hex. number
*
* @param users Users component string
* @return A string containing a hex number
*/
private static String parseUsers(String users)
{
return Long.toHexString( calculateIds(users) );
}
/**
* Converts a resources string to a hex. number
*
* @param resources Resources component string
* @return A string containing a hex number
*/
private static String parseResources(String resources)
{
long ret = 0;
String[] resourcesComponents = resources.split("/");
if( resourcesComponents.length != 2 )
{
// TODO: throw "Resource '#{resources}' malformed"
return "";
}
for( String resource : resourcesComponents[0].split("\\+") )
{
resource = resource.toUpperCase();
if( !RESOURCES.containsKey(resource) )
{
// TODO: throw "Resource '#{resource}' does not exist"
}
ret += RESOURCES.get(resource);
}
ret += calculateIds(resourcesComponents[1]);
return Long.toHexString(ret);
}
/**
* Converts a rights string to a hex. number
*
* @param rights Rights component string
* @return A string containing a hex number
*/
private static String parseRights(String rights)
{
long ret = 0;
for( String right : rights.split("\\+") )
{
right = right.toUpperCase();
if( !RIGHTS.containsKey(right) )
{
// TODO throw "Right '#{right}' does not exist"
return "";
}
ret += RIGHTS.get(right);
}
return Long.toHexString(ret);
}
/**
* Calculates the numeric value for a String containing an individual
* (#id), group (@id) or all (*) ID component
*
* @param id Rule Id string
* @return the numeric value for the given id_str
*/
private static long calculateIds(String id)
{
if( !id.matches("^([#@]\\d+|\\*)$") )
{
// TODO: throw "ID string '#{id_str}' malformed"
return 0;
}
long value = USERS.get( "" + id.charAt(0) );
if( id.charAt(0) != '*' )
{
value += Long.parseLong( id.substring(1) );
}
return value;
}
}

View File

@ -0,0 +1,98 @@
/*******************************************************************************
* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)
*
* Licensed 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 org.opennebula.client.acl;
import java.util.AbstractList;
import java.util.Iterator;
import org.opennebula.client.Client;
import org.opennebula.client.OneResponse;
import org.opennebula.client.Pool;
import org.opennebula.client.PoolElement;
import org.w3c.dom.Node;
/**
* This class represents an OpenNebula ACL rule pool.
* It also offers static XML-RPC call wrappers.
*/
public class AclPool extends Pool implements Iterable<Acl>{
private static final String ELEMENT_NAME = "ACL";
private static final String INFO_METHOD = "acl.info";
/**
* Creates a new ACL rule pool
* @param client XML-RPC Client.
*/
public AclPool(Client client)
{
super(ELEMENT_NAME, client);
}
@Override
public PoolElement factory(Node node)
{
return new Acl(node, client);
}
/**
* Retrieves all the hosts in the pool.
*
* @param client XML-RPC Client.
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public static OneResponse info(Client client)
{
return client.call(INFO_METHOD);
}
/**
* Loads the xml representation of the ACL rule pool.
*
* @see AclPool#info(Client)
*/
public OneResponse info()
{
OneResponse response = info(client);
super.processInfo(response);
return response;
}
public Iterator<Acl> iterator()
{
AbstractList<Acl> ab = new AbstractList<Acl>()
{
public int size()
{
return getLength();
}
public Acl get(int index)
{
return (Acl) item(index);
}
};
return ab.iterator();
}
public Acl getById(int id)
{
return (Acl) super.getById(id);
}
}

View File

@ -0,0 +1,213 @@
/*******************************************************************************
* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)
*
* Licensed 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.
******************************************************************************/
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opennebula.client.Client;
import org.opennebula.client.OneResponse;
import org.opennebula.client.acl.*;
public class AclTest
{
private static Acl acl;
private static AclPool aclPool;
private static Client client;
private static OneResponse res;
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception
{
client = new Client();
aclPool = new AclPool(client);
}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception
{
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception
{
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception
{
for(Acl rule : aclPool)
{
if( rule.id() != 0 )
{
rule.delete();
}
}
}
@Test
public void defaultRules()
{
res = aclPool.info();
assertTrue( !res.isError() );
assertEquals(1, aclPool.getLength());
}
@Test
public void hexAllocate()
{
// Allocate rule "#1 VM+HOST/@1 INFO+CREATE"
res = Acl.allocate(client, "0x100000001", "0x3200000001", "0x11");
assertTrue( !res.isError() );
aclPool.info();
acl = aclPool.getById( res.getIntMessage() );
assertNotNull(acl);
assertEquals(res.getIntMessage(), acl.id());
assertEquals(0x100000001L, acl.user());
assertEquals(0x3200000001L, acl.resource());
assertEquals(0x11L, acl.rights());
assertEquals("#1 VM+HOST/@1 CREATE+INFO", acl.toString());
}
@Test
public void numericAllocate()
{
// Allocate rule "#1 VM+HOST/@1 INFO+CREATE"
res = Acl.allocate(client, 0x100000001L, 214748364801L, 0x11L);
assertTrue( !res.isError() );
aclPool.info();
acl = aclPool.getById( res.getIntMessage() );
assertNotNull(acl);
assertEquals(res.getIntMessage(), acl.id());
assertEquals(0x100000001L, acl.user());
assertEquals(0x3200000001L, acl.resource());
assertEquals(0x11L, acl.rights());
assertEquals("#1 VM+HOST/@1 CREATE+INFO", acl.toString());
}
@Test
public void ruleAllocate()
{
res = Acl.allocate(client, "@507 IMAGE/#456 CREATE");
assertTrue( !res.isError() );
aclPool.info();
acl = aclPool.getById( res.getIntMessage() );
assertNotNull(acl);
assertEquals(res.getIntMessage(), acl.id());
assertEquals(0x2000001fbL, acl.user());
assertEquals(0x81000001c8L, acl.resource());
assertEquals(0x1L, acl.rights());
assertEquals("@507 IMAGE/#456 CREATE", acl.toString());
}
@Test
public void parseRules()
{
String[] rules = {
"#3 TEMPLATE/#0 INFO",
"#2 IMAGE/#0 INFO",
"@107 IMAGE+TEMPLATE/@100 INFO",
"* VM+IMAGE+TEMPLATE/@100 CREATE+INFO+INFO_POOL",
"#2345 VM+IMAGE+TEMPLATE/* CREATE+INFO+INFO_POOL+INFO_POOL_MINE+INSTANTIATE"
};
long[] users = {
0x100000003L,
0x100000002L,
0x20000006bL,
0x400000000L,
0x100000929L
};
long[] resources = {
0x20100000000L,
0x8100000000L,
0x28200000064L,
0x29200000064L,
0x29400000000L
};
long[] rights = {
0x10L,
0x10L,
0x10L,
0x31L,
0xf1L
};
for( int i = 0; i < rules.length; i++ )
{
res = Acl.allocate(client, rules[i]);
assertTrue( !res.isError() );
aclPool.info();
acl = aclPool.getById( res.getIntMessage() );
assertNotNull(acl);
assertEquals(res.getIntMessage(), acl.id());
assertEquals(users[i], acl.user());
assertEquals(resources[i], acl.resource());
assertEquals(rights[i], acl.rights());
}
assertTrue( true );
}
@Test
public void delete()
{
res = Acl.allocate(client, "#1 HOST/@2 INFO_POOL");
assertTrue( !res.isError() );
aclPool.info();
assertTrue( aclPool.getLength() == 2 );
res = Acl.delete(client, res.getIntMessage());
assertTrue( !res.isError() );
aclPool.info();
assertTrue( aclPool.getLength() == 1 );
}
}

View File

@ -1,5 +1,21 @@
#!/bin/bash
# -------------------------------------------------------------------------- #
# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) #
# #
# Licensed 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. #
#--------------------------------------------------------------------------- #
if [ -z $ONE_LOCATION ]; then
echo "ONE_LOCATION not defined."
exit -1
@ -42,4 +58,7 @@ let RC=RC+$?
./test.sh GroupTest
let RC=RC+$?
./test.sh AclTest
let RC=RC+$?
exit $RC

View File

@ -1,4 +1,21 @@
#!/bin/bash
# -------------------------------------------------------------------------- #
# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) #
# #
# Licensed 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. #
#--------------------------------------------------------------------------- #
# Usage: test.sh <Test_name>
# For instance: test.sh ImageTest
@ -16,6 +33,9 @@ if [ -f $VAR_LOCATION/one.db ]; then
exit -1
fi
echo "========================================================================="
echo "Doing $1"
echo "========================================================================="
PID=$$