JCLOUDS-246: Joined Hosted and Private Chef apis

Joined Hosted and Private Chef apis and renamed the provider
to Enterprise Chef.
This commit is contained in:
Ignasi Barrera 2013-08-19 20:29:42 +02:00
commit ac2a44ad6f
21 changed files with 1522 additions and 0 deletions

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.jclouds.chef</groupId>
<artifactId>chef-project</artifactId>
<version>1.7.0-SNAPSHOT</version>
<relativePath>../project/pom.xml</relativePath>
</parent>
<groupId>org.apache.jclouds.provider</groupId>
<artifactId>enterprisechef</artifactId>
<name>Apache jclouds Chef :: Enterprise</name>
<description>jclouds components to access Enterprise Chef</description>
<properties>
<test.enterprisechef.org>YOUR_ORG</test.enterprisechef.org>
<test.enterprisechef.endpoint>https://api.opscode.com/organizations/${test.enterprisechef.org}</test.enterprisechef.endpoint>
<test.enterprisechef.api-version />
<test.enterprisechef.build-version />
<test.enterprisechef.identity>YOUR_USER</test.enterprisechef.identity>
<test.enterprisechef.credential>${user.home}/.chef/${test.enterprisechef.org}/${test.enterprisechef.identity}.pem</test.enterprisechef.credential>
<jclouds.osgi.export>org.jclouds.enterprisechef*;version="${project.version}"</jclouds.osgi.export>
<jclouds.osgi.import>org.jclouds*;version="${jclouds.version}",*</jclouds.osgi.import>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.jclouds.api</groupId>
<artifactId>chef</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds.api</groupId>
<artifactId>chef</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${jclouds.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-slf4j</artifactId>
<version>${jclouds.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.9</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<test.enterprisechef.org>${test.enterprisechef.org}</test.enterprisechef.org>
<test.enterprisechef.endpoint>${test.enterprisechef.endpoint}</test.enterprisechef.endpoint>
<test.enterprisechef.api-version>${test.enterprisechef.api-version}</test.enterprisechef.api-version>
<test.enterprisechef.build-version>${test.enterprisechef.build-version}</test.enterprisechef.build-version>
<test.enterprisechef.identity>${test.enterprisechef.identity}</test.enterprisechef.identity>
<test.enterprisechef.credential>${test.enterprisechef.credential}</test.enterprisechef.credential>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,141 @@
/*
* 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 org.jclouds.enterprisechef;
import java.util.Set;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Constants;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.filters.SignedHeaderAuth;
import org.jclouds.chef.functions.ParseKeySetFromJson;
import org.jclouds.enterprisechef.binders.BindGroupNameToJsonPayload;
import org.jclouds.enterprisechef.binders.BindGroupToUpdateRequestJsonPayload;
import org.jclouds.enterprisechef.binders.GroupName;
import org.jclouds.enterprisechef.domain.Group;
import org.jclouds.enterprisechef.domain.User;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
/**
* Provides synchronous access to the Enterprise Chef Api.
*
* @author Ignasi Barrera
*/
@RequestFilters(SignedHeaderAuth.class)
@Consumes(MediaType.APPLICATION_JSON)
@Headers(keys = "X-Chef-Version", values = "{" + Constants.PROPERTY_API_VERSION + "}")
public interface EnterpriseChefApi extends ChefApi
{
/**
* Check if there exists a node with the given name.
*
* @return <code>true</code> if the specified node name exists.
*/
@Override
// Use get instead of HEAD
@Named("node:exists")
@GET
@Path("/nodes/{nodename}")
@Fallback(FalseOnNotFoundOr404.class)
boolean nodeExists(@PathParam("nodename") String nodename);
/**
* Retrieves an existing user.
*
* @param name The name of the user to get.
* @return The details of the user or <code>null</code> if not found.
*/
@Named("user:get")
@GET
@Path("/users/{name}")
@Fallback(NullOnNotFoundOr404.class)
User getUser(@PathParam("name") String name);
/**
* List all existing groups.
*
* @return The list of groups.
*/
@Named("group:list")
@GET
@Path("/groups")
@ResponseParser(ParseKeySetFromJson.class)
Set<String> listGroups();
/**
* Retrieves an existing group.
*
* @param name The name of the group to get.
* @return The details of the group or <code>null</code> if not found.
*/
@Named("group:get")
@GET
@Path("/groups/{name}")
@Fallback(NullOnNotFoundOr404.class)
Group getGroup(@PathParam("name") String name);
/**
* Creates a new group.
*
* @param name The name of the group to create.
*/
@Named("group:create")
@POST
@Path("/groups")
void createGroup(@BinderParam(BindGroupNameToJsonPayload.class) String name);
/**
* Updates a group.
* <p>
* This method can be used to add actors (clients, groups) to the group.
*
* @param group The group with the updated information.
*/
@Named("group:update")
@PUT
@Path("/groups/{name}")
void updateGroup(
@PathParam("name") @ParamParser(GroupName.class) @BinderParam(BindGroupToUpdateRequestJsonPayload.class) Group group);
/**
* Deletes a group.
*
* @param name The name of the group to delete.
*/
@Named("group:delete")
@DELETE
@Path("/groups/{name}")
void deleteGroup(@PathParam("name") String name);
}

View File

@ -0,0 +1,86 @@
/*
* 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 org.jclouds.enterprisechef;
import java.net.URI;
import java.util.Properties;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.ChefApiMetadata;
import org.jclouds.chef.ChefContext;
import org.jclouds.chef.config.ChefBootstrapModule;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.enterprisechef.config.EnterpriseChefHttpApiModule;
import org.jclouds.ohai.config.JMXOhaiModule;
import org.jclouds.rest.internal.BaseHttpApiMetadata;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
* Implementation of {@link ApiMetadata} for the Enterprise Chef api.
*
* @author Adrian Cole
*/
public class EnterpriseChefApiMetadata extends BaseHttpApiMetadata<EnterpriseChefApi> {
@Override
public Builder toBuilder() {
return new Builder().fromApiMetadata(this);
}
public EnterpriseChefApiMetadata() {
this(new Builder());
}
protected EnterpriseChefApiMetadata(Builder builder) {
super(builder);
}
public static Properties defaultProperties() {
return ChefApiMetadata.defaultProperties();
}
public static class Builder extends BaseHttpApiMetadata.Builder<EnterpriseChefApi, Builder> {
protected Builder() {
id("enterprisechef")
.name("Enterprise Chef Api")
.identityName("User")
.credentialName("Certificate")
.version(ChefApi.VERSION)
.documentation(URI.create("http://www.opscode.com/support"))
.defaultEndpoint("https://api.opscode.com")
.view(ChefContext.class)
.defaultProperties(EnterpriseChefApiMetadata.defaultProperties())
.defaultModules(
ImmutableSet.<Class<? extends Module>> of(EnterpriseChefHttpApiModule.class,
ChefParserModule.class, ChefBootstrapModule.class, JMXOhaiModule.class));
}
@Override
public EnterpriseChefApiMetadata build() {
return new EnterpriseChefApiMetadata(this);
}
@Override
protected Builder self() {
return this;
}
}
}

View File

@ -0,0 +1,88 @@
/*
* 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 org.jclouds.enterprisechef;
import java.net.URI;
import java.util.Properties;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.providers.internal.BaseProviderMetadata;
/**
* Implementation of @ link org.jclouds.types.ProviderMetadata} for Enterprise Chef
*
* @author Adrian Cole
*/
public class EnterpriseChefProviderMetadata extends BaseProviderMetadata
{
public static Builder builder()
{
return new Builder();
}
@Override
public Builder toBuilder()
{
return builder().fromProviderMetadata(this);
}
public EnterpriseChefProviderMetadata()
{
super(builder());
}
public EnterpriseChefProviderMetadata(Builder builder)
{
super(builder);
}
public static Properties defaultProperties()
{
Properties properties = new Properties();
return properties;
}
public static class Builder extends BaseProviderMetadata.Builder
{
protected Builder()
{
id("enterprisechef") //
.name("OpsCode Enterprise Chef") //
.endpoint("https://api.opscode.com") //
.homepage(URI.create("https://manage.opscode.com")) //
.console(URI.create("https://manage.opscode.com")) //
.apiMetadata(new EnterpriseChefApiMetadata()) //
.defaultProperties(EnterpriseChefProviderMetadata.defaultProperties());
}
@Override
public EnterpriseChefProviderMetadata build()
{
return new EnterpriseChefProviderMetadata(this);
}
@Override
public Builder fromProviderMetadata(ProviderMetadata in)
{
super.fromProviderMetadata(in);
return this;
}
}
}

View File

@ -0,0 +1,42 @@
/*
* 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 org.jclouds.enterprisechef.binders;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Singleton;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.BindToStringPayload;
/**
* Binds the name of a group to the json payload.
*
* @author Ignasi Barrera
*/
@Singleton
public class BindGroupNameToJsonPayload extends BindToStringPayload {
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
super.bindToRequest(request, String.format("{\"groupname\":\"%s\"}", checkNotNull(payload, "payload")));
request.getPayload().getContentMetadata().setContentType(MediaType.APPLICATION_JSON);
return request;
}
}

View File

@ -0,0 +1,81 @@
/*
* 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 org.jclouds.enterprisechef.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.enterprisechef.domain.Group;
import org.jclouds.http.HttpRequest;
import org.jclouds.json.Json;
import org.jclouds.rest.binders.BindToJsonPayload;
/**
* Binds a group to the payload expected for the Put method in the Enterprise Chef
* Api.
*
* @author Ignasi Barrera
*/
@Singleton
public class BindGroupToUpdateRequestJsonPayload extends BindToJsonPayload {
@Inject
public BindGroupToUpdateRequestJsonPayload(Json jsonBinder) {
super(jsonBinder);
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
checkArgument(checkNotNull(payload, "payload") instanceof Group, "this binder is only valid for Group objects");
GroupUpdateRequest updateGroup = new GroupUpdateRequest((Group) payload);
return super.bindToRequest(request, updateGroup);
}
@SuppressWarnings("unused")
private static class GroupUpdateRequest {
private String name;
private String groupname;
private String orgname;
private ActorConfiguration actors;
public GroupUpdateRequest(Group group) {
this.name = group.getName();
this.groupname = group.getGroupname();
this.orgname = group.getOrgname();
this.actors = new ActorConfiguration(group);
}
}
@SuppressWarnings("unused")
private static class ActorConfiguration {
private Set<String> clients;
private Set<String> groups;
private Set<String> users;
public ActorConfiguration(Group group) {
this.clients = group.getClients();
this.groups = group.getGroups();
this.users = group.getUsers();
}
}
}

View File

@ -0,0 +1,40 @@
/*
* 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 org.jclouds.enterprisechef.binders;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Singleton;
import org.jclouds.enterprisechef.domain.Group;
import com.google.common.base.Function;
/**
* Gets the name of a group.
*
* @author Ignasi Barrera
*/
@Singleton
public class GroupName implements Function<Object, String> {
@Override
public String apply(Object from) {
return ((Group) checkNotNull(from, "from")).getGroupname();
}
}

View File

@ -0,0 +1,38 @@
/*
* 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 org.jclouds.enterprisechef.config;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.BaseChefHttpApiModule;
import org.jclouds.enterprisechef.EnterpriseChefApi;
import org.jclouds.rest.ConfiguresHttpApi;
/**
* Configures the Enterprise Chef connection.
*
* @author Ignasi Barrera
*/
@ConfiguresHttpApi
public class EnterpriseChefHttpApiModule extends BaseChefHttpApiModule<EnterpriseChefApi> {
@Override
protected void configure() {
super.configure();
bind(ChefApi.class).to(EnterpriseChefApi.class);
}
}

View File

@ -0,0 +1,141 @@
/*
* 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 org.jclouds.enterprisechef.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import com.google.common.collect.Sets;
/**
* Group object.
*
* @author Ignasi Barrera
*/
public class Group {
private String name;
private String groupname;
private String orgname;
private Set<String> actors = Sets.newHashSet();
private Set<String> clients = Sets.newHashSet();
private Set<String> groups = Sets.newHashSet();
private Set<String> users = Sets.newHashSet();
// When creating groups, only the group name property is considered
public Group(String groupname) {
this.groupname = checkNotNull(groupname, "groupname");
}
// Only for deserialization
Group() {
}
public String getName() {
return name;
}
public String getGroupname() {
return groupname;
}
public String getOrgname() {
return orgname;
}
public Set<String> getActors() {
return actors;
}
public Set<String> getClients() {
return clients;
}
public Set<String> getGroups() {
return groups;
}
public Set<String> getUsers() {
return users;
}
public void setClients(Set<String> clients) {
this.clients = clients;
}
public void setGroups(Set<String> groups) {
this.groups = groups;
}
public void setUsers(Set<String> users) {
this.users = users;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (groupname == null ? 0 : groupname.hashCode());
result = prime * result + (name == null ? 0 : name.hashCode());
result = prime * result + (orgname == null ? 0 : orgname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Group other = (Group) obj;
if (groupname == null) {
if (other.groupname != null) {
return false;
}
} else if (!groupname.equals(other.groupname)) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
if (orgname == null) {
if (other.orgname != null) {
return false;
}
} else if (!orgname.equals(other.orgname)) {
return false;
}
return true;
}
@Override
public String toString() {
return "Group [name=" + name + ", groupname=" + groupname + ", orgname=" + orgname + ", actors=" + actors
+ ", clients=" + clients + ", groups=" + groups + ", users=" + users + "]";
}
}

View File

@ -0,0 +1,161 @@
/*
* 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 org.jclouds.enterprisechef.domain;
import java.security.PublicKey;
import com.google.gson.annotations.SerializedName;
/**
* User object.
*
* @author Ignasi Barrera
*/
public class User {
private String username;
@SerializedName("first_name")
private String firstName;
@SerializedName("middle_name")
private String middleName;
@SerializedName("last_name")
private String lastName;
@SerializedName("display_name")
private String displayName;
private String email;
@SerializedName("public_key")
private PublicKey publicKey;
// TODO: Add a constructor to allow creating users. Need an Enterprise Chef instance!
// Only for deserialization
User() {
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (displayName == null ? 0 : displayName.hashCode());
result = prime * result + (email == null ? 0 : email.hashCode());
result = prime * result + (firstName == null ? 0 : firstName.hashCode());
result = prime * result + (lastName == null ? 0 : lastName.hashCode());
result = prime * result + (middleName == null ? 0 : middleName.hashCode());
result = prime * result + (publicKey == null ? 0 : publicKey.hashCode());
result = prime * result + (username == null ? 0 : username.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
User other = (User) obj;
if (displayName == null) {
if (other.displayName != null) {
return false;
}
} else if (!displayName.equals(other.displayName)) {
return false;
}
if (email == null) {
if (other.email != null) {
return false;
}
} else if (!email.equals(other.email)) {
return false;
}
if (firstName == null) {
if (other.firstName != null) {
return false;
}
} else if (!firstName.equals(other.firstName)) {
return false;
}
if (lastName == null) {
if (other.lastName != null) {
return false;
}
} else if (!lastName.equals(other.lastName)) {
return false;
}
if (middleName == null) {
if (other.middleName != null) {
return false;
}
} else if (!middleName.equals(other.middleName)) {
return false;
}
if (publicKey == null) {
if (other.publicKey != null) {
return false;
}
} else if (!publicKey.equals(other.publicKey)) {
return false;
}
if (username == null) {
if (other.username != null) {
return false;
}
} else if (!username.equals(other.username)) {
return false;
}
return true;
}
public String getUsername() {
return username;
}
public String getFirstName() {
return firstName;
}
public String getMiddleName() {
return middleName;
}
public String getLastName() {
return lastName;
}
public String getDisplayName() {
return displayName;
}
public String getEmail() {
return email;
}
public PublicKey getPublicKey() {
return publicKey;
}
@Override
public String toString() {
return "User [username=" + username + ", firstName=" + firstName + ", middleName=" + middleName + ", lastName="
+ lastName + ", displayName=" + displayName + ", email=" + email + ", publicKey=" + publicKey + "]";
}
}

View File

@ -0,0 +1 @@
org.jclouds.enterprisechef.EnterpriseChefProviderMetadata

View File

@ -0,0 +1,222 @@
/*
* 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 org.jclouds.enterprisechef;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.util.Set;
import javax.ws.rs.core.MediaType;
import org.jclouds.chef.BaseChefApiExpectTest;
import org.jclouds.chef.ChefApi;
import org.jclouds.date.TimeStamp;
import org.jclouds.enterprisechef.EnterpriseChefApi;
import org.jclouds.enterprisechef.EnterpriseChefProviderMetadata;
import org.jclouds.enterprisechef.config.EnterpriseChefHttpApiModule;
import org.jclouds.enterprisechef.domain.Group;
import org.jclouds.enterprisechef.domain.User;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
* Expect tests for the {@link EnterpriseChefApi} class.
*
* @author Ignasi Barrera
*/
@Test(groups = "unit", testName = "EnterpriseChefApiExpectTest")
public class EnterpriseChefApiExpectTest extends BaseChefApiExpectTest<EnterpriseChefApi> {
public EnterpriseChefApiExpectTest() {
provider = "enterprisechef";
}
public void testGetUserReturns2xx() {
EnterpriseChefApi api = requestSendsResponse(
signed(HttpRequest.builder() //
.method("GET") //
.endpoint("https://api.opscode.com/users/nacx") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON).build()), //
HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/user.json", MediaType.APPLICATION_JSON)) //
.build());
User user = api.getUser("nacx");
assertEquals(user.getUsername(), "nacx");
assertEquals(user.getDisplayName(), "Ignasi Barrera");
}
public void testGetUserReturns404() {
EnterpriseChefApi api = requestSendsResponse(signed(HttpRequest.builder() //
.method("GET") //
.endpoint("https://api.opscode.com/users/foo") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON) //
.build()), //
HttpResponse.builder().statusCode(404).build());
assertNull(api.getUser("foo"));
}
public void testListGroups() {
EnterpriseChefApi api = requestSendsResponse(
signed(HttpRequest.builder() //
.method("GET") //
.endpoint("https://api.opscode.com/groups") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON).build()), //
HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/groups.json", MediaType.APPLICATION_JSON)) //
.build());
Set<String> groups = api.listGroups();
assertEquals(groups.size(), 5);
assertTrue(groups.contains("admins"));
}
public void testGetGroupReturns2xx() {
EnterpriseChefApi api = requestSendsResponse(
signed(HttpRequest.builder() //
.method("GET") //
.endpoint("https://api.opscode.com/groups/admins") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON).build()), //
HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/group.json", MediaType.APPLICATION_JSON)) //
.build());
Group group = api.getGroup("admins");
assertEquals(group.getName(), "admins");
assertEquals(group.getGroupname(), "admins");
}
public void testGetGroupReturns404() {
EnterpriseChefApi api = requestSendsResponse(signed(HttpRequest.builder() //
.method("GET") //
.endpoint("https://api.opscode.com/groups/foo") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON) //
.build()), //
HttpResponse.builder().statusCode(404).build());
assertNull(api.getGroup("foo"));
}
public void testCreateGroupReturns2xx() {
EnterpriseChefApi api = requestSendsResponse(signed(HttpRequest.builder() //
.method("POST") //
.endpoint("https://api.opscode.com/groups") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON) //
.payload(payloadFromStringWithContentType("{\"groupname\":\"foo\"}", MediaType.APPLICATION_JSON)) //
.build()), //
HttpResponse.builder().statusCode(201).build());
api.createGroup("foo");
}
public void testDeleteGroupReturns2xx() {
EnterpriseChefApi api = requestSendsResponse(signed(HttpRequest.builder() //
.method("DELETE") //
.endpoint("https://api.opscode.com/groups/foo") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON) //
.build()), //
HttpResponse.builder().statusCode(200).build());
api.deleteGroup("foo");
}
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testDeleteGroupFailsOn404() {
EnterpriseChefApi api = requestSendsResponse(signed(HttpRequest.builder() //
.method("DELETE") //
.endpoint("https://api.opscode.com/groups/foo") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON) //
.build()), //
HttpResponse.builder().statusCode(404).build());
api.deleteGroup("foo");
}
public void testUpdateGroupReturns2xx() {
EnterpriseChefApi api = requestSendsResponse(signed(HttpRequest.builder() //
.method("PUT") //
.endpoint("https://api.opscode.com/groups/admins") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON) //
.payload(payloadFromResourceWithContentType("/group-update.json", MediaType.APPLICATION_JSON)) //
.build()), //
HttpResponse.builder().statusCode(200).build());
Group group = new Group("admins");
group.setClients(ImmutableSet.of("abiquo"));
group.setGroups(ImmutableSet.of("admins"));
group.setUsers(ImmutableSet.of("nacx"));
api.updateGroup(group);
}
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testUpdateGroupFailsOn404() {
EnterpriseChefApi api = requestSendsResponse(signed(HttpRequest.builder() //
.method("PUT") //
.endpoint("https://api.opscode.com/groups/admins") //
.addHeader("X-Chef-Version", ChefApi.VERSION) //
.addHeader("Accept", MediaType.APPLICATION_JSON) //
.payload(payloadFromResourceWithContentType("/group-update.json", MediaType.APPLICATION_JSON)) //
.build()), //
HttpResponse.builder().statusCode(404).build());
Group group = new Group("admins");
group.setClients(ImmutableSet.of("abiquo"));
group.setGroups(ImmutableSet.of("admins"));
group.setUsers(ImmutableSet.of("nacx"));
api.updateGroup(group);
}
@Override
protected Module createModule() {
return new TestEnterpriseChefRestClientModule();
}
@ConfiguresRestClient
static class TestEnterpriseChefRestClientModule extends EnterpriseChefHttpApiModule {
@Override
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return "timestamp";
}
}
@Override
protected ProviderMetadata createProviderMetadata() {
return new EnterpriseChefProviderMetadata();
}
}

View File

@ -0,0 +1,121 @@
/*
* 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 org.jclouds.enterprisechef;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.util.Set;
import java.util.UUID;
import org.jclouds.chef.internal.BaseChefApiLiveTest;
import org.jclouds.enterprisechef.EnterpriseChefApi;
import org.jclouds.enterprisechef.domain.Group;
import org.jclouds.enterprisechef.domain.User;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of the EnterpriseChefApi.
*
* @author Adrian Cole
*/
@Test(groups = "live", singleThreaded = true, testName = "EnterpriseChefApiLiveTest")
public class EnterpriseChefApiLiveTest extends BaseChefApiLiveTest<EnterpriseChefApi> {
private static final String GROUP_NAME = System.getProperty("user.name") + "-jcloudstest";
private static final String ORG_NAME = System.getProperty("test.enterprisechef.org");
public EnterpriseChefApiLiveTest() {
provider = "enterprisechef";
}
@Override
@Test
public void testSearchClientsWithOptions() throws Exception {
// This test will fail because Enterprise Chef does not index client name.
// Once it is fixes, the test should succeed.
// See: http://tickets.opscode.com/browse/CHEF-2477
super.testSearchClientsWithOptions();
}
public void testGetUser() {
User user = api.getUser(identity);
assertEquals(user.getUsername(), identity);
assertNotNull(user.getPublicKey());
}
public void testGetUnexistingUser() {
User user = api.getUser(UUID.randomUUID().toString());
assertNull(user);
}
public void testListGroups() {
Set<String> groups = api.listGroups();
assertNotNull(groups);
assertFalse(groups.isEmpty());
}
public void testGetUnexistingGroup() {
Group group = api.getGroup(UUID.randomUUID().toString());
assertNull(group);
}
public void testCreateGroup() {
api.createGroup(GROUP_NAME);
Group group = api.getGroup(GROUP_NAME);
assertNotNull(group);
assertEquals(group.getGroupname(), GROUP_NAME);
}
@Test(dependsOnMethods = "testCreateGroup")
public void testUpdateGroup() {
Group group = api.getGroup(GROUP_NAME);
group.setUsers(ImmutableSet.of(identity));
group.setClients(ImmutableSet.of(ORG_NAME + "-validator"));
api.updateGroup(group);
group = api.getGroup(GROUP_NAME);
assertNotNull(group);
assertTrue(group.getUsers().contains(identity));
assertTrue(group.getClients().contains(ORG_NAME + "-validator"));
}
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testUpdateUnexistingGroup() {
api.updateGroup(new Group(UUID.randomUUID().toString()));
}
@Test(dependsOnMethods = "testUpdateGroup")
public void testDeleteGroup() {
api.deleteGroup(GROUP_NAME);
Group group = api.getGroup(GROUP_NAME);
assertNull(group);
}
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testDeleteUnexistingGroup() {
api.deleteGroup(UUID.randomUUID().toString());
}
}

View File

@ -0,0 +1,35 @@
/*
* 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 org.jclouds.enterprisechef;
import org.jclouds.enterprisechef.EnterpriseChefApiMetadata;
import org.jclouds.enterprisechef.EnterpriseChefProviderMetadata;
import org.jclouds.providers.internal.BaseProviderMetadataTest;
import org.testng.annotations.Test;
/**
* Unit tests for the {@link EnterpriseChefProviderMetadata} class.
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "EnterpriseChefProviderTest")
public class EnterpriseChefProviderMetadataTest extends BaseProviderMetadataTest {
public EnterpriseChefProviderMetadataTest() {
super(new EnterpriseChefProviderMetadata(), new EnterpriseChefApiMetadata());
}
}

View File

@ -0,0 +1,52 @@
/*
* 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 org.jclouds.enterprisechef.binders;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URI;
import org.jclouds.enterprisechef.binders.BindGroupNameToJsonPayload;
import org.jclouds.http.HttpRequest;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
/**
* Unit tests for the {@link BindGroupNameToJsonPayload} class.
*
* @author Ignasi Barrera
*/
@Test(groups = "unit", testName = "BindGroupNameToJsonPayloadTest")
public class BindGroupNameToJsonPayloadTest {
@Test(expectedExceptions = NullPointerException.class)
public void testInvalidNullInput() {
BindGroupNameToJsonPayload binder = new BindGroupNameToJsonPayload();
HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build();
binder.bindToRequest(request, null);
}
public void testBindString() throws IOException {
BindGroupNameToJsonPayload binder = new BindGroupNameToJsonPayload();
HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build();
HttpRequest newRequest = binder.bindToRequest(request, "foo");
String payload = Strings2.toStringAndClose(newRequest.getPayload().getInput());
assertEquals(payload, "{\"groupname\":\"foo\"}");
}
}

View File

@ -0,0 +1,89 @@
/*
* 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 org.jclouds.enterprisechef.binders;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URI;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.enterprisechef.binders.BindGroupToUpdateRequestJsonPayload;
import org.jclouds.enterprisechef.domain.Group;
import org.jclouds.http.HttpRequest;
import org.jclouds.json.config.GsonModule;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Unit tests for the {@link BindGroupToUpdateRequestJsonPayload} class.
*
* @author Ignasi Barrera
*/
@Test(groups = "unit", testName = "BindGroupToUpdateRequestJsonPayloadTest")
public class BindGroupToUpdateRequestJsonPayloadTest {
private Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(String.class).annotatedWith(ApiVersion.class).toInstance(ChefApi.VERSION);
}
}, new ChefParserModule(), new GsonModule());
private BindGroupToUpdateRequestJsonPayload binder = injector.getInstance(BindGroupToUpdateRequestJsonPayload.class);
@Test(expectedExceptions = NullPointerException.class)
public void testInvalidNullInput() {
HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build();
binder.bindToRequest(request, null);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testInvalidTypeInput() {
HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build();
binder.bindToRequest(request, new Object());
}
public void testBindOnlyName() throws IOException {
HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build();
HttpRequest newRequest = binder.bindToRequest(request, new Group("foo"));
String payload = Strings2.toStringAndClose(newRequest.getPayload().getInput());
assertEquals(payload, "{\"groupname\":\"foo\",\"actors\":{\"clients\":[],\"groups\":[],\"users\":[]}}");
}
public void testBindNameAndLists() throws IOException {
Group group = new Group("foo");
group.setClients(ImmutableSet.of("nacx-validator"));
group.setGroups(ImmutableSet.of("admins"));
group.setUsers(ImmutableSet.of("nacx"));
HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build();
HttpRequest newRequest = binder.bindToRequest(request, group);
String payload = Strings2.toStringAndClose(newRequest.getPayload().getInput());
assertEquals(payload,
"{\"groupname\":\"foo\",\"actors\":{\"clients\":[\"nacx-validator\"],\"groups\":[\"admins\"],\"users\":[\"nacx\"]}}");
}
}

View File

@ -0,0 +1,43 @@
/*
* 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 org.jclouds.enterprisechef.binders;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import org.jclouds.enterprisechef.binders.GroupName;
import org.jclouds.enterprisechef.domain.Group;
import org.testng.annotations.Test;
/**
* Unit tests for the {@link GroupName} class.
*
* @author Ignasi Barrera
*/
@Test(groups = "unit", testName = "GroupNameTest")
public class GroupNameTest {
@Test(expectedExceptions = NullPointerException.class)
public void testInvalidNullInput() {
new GroupName().apply(null);
}
public void testApplyGroupName() throws IOException {
assertEquals(new GroupName().apply(new Group("foo")), "foo");
}
}

View File

@ -0,0 +1 @@
{"groupname":"admins","actors":{"clients":["abiquo"],"groups":["admins"],"users":["nacx"]}}

View File

@ -0,0 +1,14 @@
{
"actors" : [ "abiquo",
"nacx",
"pivotal"
],
"clients" : [ "abiquo" ],
"groupname" : "admins",
"groups" : [ "billing-admins" ],
"name" : "admins",
"orgname" : "nacx",
"users" : [ "nacx",
"pivotal"
]
}

View File

@ -0,0 +1,7 @@
{
"965f2db33d302ed4625d172e0bc36920" : "https://api.opscode.com/organizations/nacx/groups/965f2db33d302ed4625d172e0bc36920",
"admins" : "https://api.opscode.com/organizations/nacx/groups/admins",
"billing-admins" : "https://api.opscode.com/organizations/nacx/groups/billing-admins",
"clients" : "https://api.opscode.com/organizations/nacx/groups/clients",
"users" : "https://api.opscode.com/organizations/nacx/groups/users"
}

View File

@ -0,0 +1,9 @@
{
"display_name" : "Ignasi Barrera",
"email" : "myemail@enterprisechef.org",
"first_name" : "Ignasi",
"last_name" : "Barrera",
"middle_name" : "",
"public_key" : "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAp0ytgXbPzqJwOOixn7bTa6VAiNvVIOn+yDPoWbyEfc0li93BHIwv\n01KW/mn55IXnSbMw86rdxisvwPHFfb7URuKuTzME6yrphBiancmNjushZZeBWb8j\nqJhnFIKbaaOqew0LZSyG9ycYODB/HDK/pWTV4Bd1OtLHBNFrnIf+r3HOjJsa4rmK\nWXgSQIQO7be/iRHysApV9tfVH8lo1ETnA08JTrQwDgo9St9YNbydb5V0CiLiQsOa\nIbY09buUK9lXthh/rrRVbGbSwQM6OYdXIEZTN2BFvQ0p5pH8AiTwFqb0ICO46a0S\njfGcXNjC/QfHljAPY3T5xyIOODM8afHCnwIDAQAB\n-----END RSA PUBLIC KEY-----\n",
"username" : "nacx"
}