Creating a straman for allowing external tools (e.g. Nagios) to manage 'manageable' services and or resources from a tuscany domain

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1297253 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
lresende 2012-03-05 22:19:12 +00:00
parent 94c82a74de
commit f742a208ac
12 changed files with 645 additions and 1 deletions

View file

@ -9,8 +9,11 @@ Bundle-Version: 2.0.0
Bundle-ManifestVersion: 2
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-Description: Apache Tuscany SCA Node Manager
Import-Package: javax.ws.rs,
Import-Package: javax.servlet;version="2.5.0",
javax.ws.rs,
javax.ws.rs.core,
org.apache.tuscany.sca.assembly;version="2.0.0",
org.apache.tuscany.sca.interfacedef;version="2.0.0",
org.apache.tuscany.sca.node;version="2.0.0",
org.apache.tuscany.sca.node.configuration;version="2.0.0",
org.apache.tuscany.sca.node.extensibility;version="2.0.0",

View file

@ -127,6 +127,25 @@
<version>2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tuscany.sca</groupId>
<artifactId>tuscany-host-jetty</artifactId>

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.apache.tuscany.sca.node.manager;
import java.util.List;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.oasisopen.sca.annotation.Remotable;
@Remotable
public interface DomainAssetManagerResource {
@GET
@Path("{domainURI}/resources/status")
List<Status> getResourceStatus(@PathParam("domainURI") @DefaultValue("default") String domainURI);
@GET
@Path("{domainURI}/services/status")
List<Status> getServiceStatus(@PathParam("domainURI") @DefaultValue("default") String domainURI);
}

View file

@ -0,0 +1,41 @@
/*
* 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.apache.tuscany.sca.node.manager;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.oasisopen.sca.annotation.Remotable;
@Remotable
public interface ManageableResource {
/**
* Ping resource used for service monitoring
* @return
*/
@GET
@Path("/ping")
@Produces(MediaType.TEXT_HTML)
Response ping();
}

View file

@ -0,0 +1,31 @@
/*
* 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.apache.tuscany.sca.node.manager;
import org.oasisopen.sca.annotation.Remotable;
@Remotable
public interface ManageableService {
/**
* isAlive method that allow service to be managed
*/
void isAlive();
}

View file

@ -0,0 +1,85 @@
/*
* 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.apache.tuscany.sca.node.manager;
public class Status {
public static int SUCCESS = 0;
public static int FAILURE = 1;
private String name;
private String uri;
private int status;
private String statusMessage;
private long execution;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getStatusMessage() {
return statusMessage;
}
public void setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
}
public long getExecution() {
return execution;
}
public void setExecution(long execution) {
this.execution = execution;
}
@Override
public String toString() {
return "Status [name=" + name
+ ", uri="
+ uri
+ ", status="
+ status
+ ", statusMessage="
+ statusMessage
+ ", execution="
+ execution
+ "]";
}
}

View file

@ -0,0 +1,215 @@
/*
* 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.apache.tuscany.sca.node.manager.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.tuscany.sca.assembly.Binding;
import org.apache.tuscany.sca.assembly.Component;
import org.apache.tuscany.sca.assembly.Composite;
import org.apache.tuscany.sca.assembly.Service;
import org.apache.tuscany.sca.binding.rest.RESTBinding;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.core.FactoryExtensionPoint;
import org.apache.tuscany.sca.host.http.client.HttpClientFactory;
import org.apache.tuscany.sca.interfacedef.Interface;
import org.apache.tuscany.sca.node.Node;
import org.apache.tuscany.sca.node.extensibility.NodeActivator;
import org.apache.tuscany.sca.node.extensibility.NodeExtension;
import org.apache.tuscany.sca.node.manager.DomainAssetManagerResource;
import org.apache.tuscany.sca.node.manager.ManageableResource;
import org.apache.tuscany.sca.node.manager.ManageableService;
import org.apache.tuscany.sca.node.manager.Status;
import org.oasisopen.sca.annotation.Init;
public class DomainAssetManagerResourceImpl implements NodeActivator, DomainAssetManagerResource {
private static Map<String, NodeExtension> nodeMap = new ConcurrentHashMap<String,NodeExtension>();
private HttpClientFactory httpClientFactory;
public void nodeStarted(Node node) {
NodeExtension nodeExtension = (NodeExtension) node;
nodeMap.put(nodeExtension.getDomainURI(), nodeExtension);
}
public void nodeStopped(Node node) {
NodeExtension nodeExtension = (NodeExtension) node;
nodeMap.remove(nodeExtension.getDomainURI());
}
@Init
public void init() {
NodeExtension node = (NodeExtension) nodeMap.values().iterator().next();
if(node != null) {
ExtensionPointRegistry extensionPoints = node.getExtensionPointRegistry();
FactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class);
this.httpClientFactory = HttpClientFactory.getInstance(extensionPoints);
}
}
@Override
public List<Status> getResourceStatus(@PathParam("domainURI") @DefaultValue("default") String domainURI) {
if( ! nodeMap.containsKey(domainURI)) {
throw new WebApplicationException(404);
}
NodeExtension node = nodeMap.get(domainURI);
Composite domainComposite = node.getDomainComposite();
List<Status> statuses = new ArrayList<Status>();
for(Component component : domainComposite.getComponents()) {
for(Service service : component.getServices()) {
Interface interfaceContract = service.getInterfaceContract().getInterface();
if(ManageableResource.class.getName().equals(interfaceContract.toString())) {
Binding binding = service.getBinding(RESTBinding.class);
if(binding != null) {
Status status = new Status();
status.setName(component.getName());
status.setUri(binding.getURI());
try {
Timer t = new Timer();
status = testResource(status);
status.setExecution(t.elapsed(TimeUnit.MILLISECONDS));
status.setStatus(Status.SUCCESS);
} catch (Exception e) {
status.setStatus(Status.FAILURE);
status.setStatusMessage(e.getMessage());
}
statuses.add(status);
}
}
}
}
return statuses;
}
@Override
public List<Status> getServiceStatus(@PathParam("domainURI") @DefaultValue("default") String domainURI) {
if( ! nodeMap.containsKey(domainURI)) {
throw new WebApplicationException(404);
}
NodeExtension node = nodeMap.get(domainURI);
Composite domainComposite = node.getDomainComposite();
List<Status> statuses = new ArrayList<Status>();
for(Component component : domainComposite.getComponents()) {
for(Service service : component.getServices()) {
Interface interfaceContract = service.getInterfaceContract().getInterface();
if(ManageableService.class.getName().equals(interfaceContract.toString())) {
Status status = new Status();
status.setName(component.getName());
status.setUri(service.getBindings().get(0).getURI());
try {
String serviceName = component.getName() +"/" + service.getName();
ManageableService serviceInstance = node.getService(ManageableService.class, component.getName());
Timer t = new Timer();
serviceInstance.isAlive();
status.setExecution(t.elapsed(TimeUnit.MILLISECONDS));
status.setStatus(Status.SUCCESS);
} catch (Exception e) {
status.setStatus(Status.FAILURE);
status.setStatusMessage(e.getMessage());
}
statuses.add(status);
}
}
}
return statuses;
}
private Status testResource(Status status) throws IOException {
// Create an HTTP client
HttpClient httpClient = httpClientFactory.createHttpClient();
HttpGet request = new HttpGet(status.getUri() + "ping");
//request.addHeader("Accept","application/json");
HttpResponse response = httpClient.execute(request);
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new IOException("Error invoking service at '" + request.getURI() +"' => " + response.getStatusLine().getReasonPhrase());
}
if (httpClient != null) {
httpClient.getConnectionManager().shutdown();
}
return status;
}
class Timer {
Date time;
long t;
public Timer() {
reset();
}
public void reset() {
time = new Date();
t = System.nanoTime();
}
public Date time() {
return time;
}
public long elapsed(TimeUnit timeUnit) {
long elapsedTime = elapsed();
return timeUnit.convert(elapsedTime, TimeUnit.NANOSECONDS);
}
public void print(String s, TimeUnit timeUnit) {
long elapsedTime = elapsed();
System.out.println(s + ": " + timeUnit.convert(elapsedTime, TimeUnit.NANOSECONDS) + "ms");
}
private long elapsed() {
return System.nanoTime() - t;
}
}
}

View file

@ -16,3 +16,4 @@
# under the License.
# Implementation class for the ModuleActivator
org.apache.tuscany.sca.node.manager.impl.DomainCompositeResourceImpl;ranking=100
org.apache.tuscany.sca.node.manager.impl.DomainAssetManagerResourceImpl;ranking=101

View file

@ -0,0 +1,85 @@
/*
* 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.apache.tuscany.sca.node.manager;
import org.apache.tuscany.sca.node.Contribution;
import org.apache.tuscany.sca.node.ContributionLocationHelper;
import org.apache.tuscany.sca.node.Node;
import org.apache.tuscany.sca.node.NodeFactory;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
public class DomainAssetManagerResourceTestCase {
private static String SERVICE_URL;
private static Node node;
@BeforeClass
public static void init() throws Exception {
try {
String contribution = ContributionLocationHelper.getContributionLocation(DomainCompositeResourceTestCase.class);
node = NodeFactory.newInstance().createNode("node-asset-manager-test.composite", new Contribution("node-manager", contribution));
node.start();
SERVICE_URL = node.getEndpointAddress("NodeAssetManagerComponent");
System.out.println(">>" + SERVICE_URL);
} catch (Exception e) {
e.printStackTrace();
}
}
@AfterClass
public static void destroy() throws Exception {
if (node != null) {
node.stop();
}
}
@Test
public void testServiceManagement() throws Exception {
WebConversation wc = new WebConversation();
WebRequest request = new GetMethodWebRequest(SERVICE_URL + "default/services/status");
request.setHeaderField("Accept","application/json");
WebResponse response = wc.getResource(request);
Assert.assertEquals(200, response.getResponseCode());
System.out.println(">>>" + response.getText());
}
@Test
public void testResourceManagement() throws Exception {
WebConversation wc = new WebConversation();
WebRequest request = new GetMethodWebRequest(SERVICE_URL + "default/resources/status");
request.setHeaderField("Accept","application/json");
WebResponse response = wc.getResource(request);
Assert.assertEquals(200, response.getResponseCode());
System.out.println(">>>" + response.getText());
}
}

View file

@ -0,0 +1,34 @@
/*
* 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 services;
import javax.ws.rs.core.Response;
import org.apache.tuscany.sca.node.manager.ManageableResource;
public class MyResourceImpl implements ManageableResource {
@Override
public Response ping() {
System.out.println(">>> ping");
return Response.ok("pong").build();
}
}

View file

@ -0,0 +1,32 @@
/*
* 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 services;
import org.apache.tuscany.sca.node.manager.ManageableService;
public class MyServiceImpl implements ManageableService {
@Override
public void isAlive() {
System.out.println(">>> isAlive");
}
}

View file

@ -0,0 +1,55 @@
<?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.
-->
<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"
targetNamespace="http://node-manager"
name="NodeAssetManager">
<component name="NodeAssetManagerComponent">
<implementation.java class="org.apache.tuscany.sca.node.manager.impl.DomainAssetManagerResourceImpl"/>
<service name="DomainAssetManagerResource">
<tuscany:binding.rest uri="/services/manager" />
</service>
</component>
<component name="Resource">
<implementation.java class="services.MyResourceImpl"/>
<service name="ManageableResource">
<tuscany:binding.rest uri="/services/resource" />
</service>
</component>
<!-- -->
<component name="AnotherResource">
<implementation.java class="services.MyResourceImpl"/>
<service name="ManageableResource">
<tuscany:binding.rest uri="/services/another/resource" />
</service>
</component>
<!-- -->
<component name="Service">
<implementation.java class="services.MyServiceImpl"/>
<service name="ManageableService">
<binding.sca />
</service>
</component>
</composite>