Modern enterprise applications are most often deployed on distributed infrastructure such as a private or public cloud environment, instead of on a single server. This is done to distribute the application load, to replicate the application to guarantee availability or to exploit dedicated hardware for certain application functionality (for example, a database server).
The unit of management is often no longer a single physical machine. Server infrastructure is nowadays mostly offered in a virtualized fashion, such as hardware virtualization using a hypervisor or operating system virtualization using containers. Potentially these can also be hierarchically managed, for example having multiple containers running inside a virtual machine. Therefore, it becomes key to manage an application running on a cluster of such (virtual) machines and/or containers.
Also in the context of the Internet of Things (IoT), often a number of gateway devices is deployed in the network that connect various sensors and actuators creating a smart environment. Again, it becomes key to discover and manage these devices, and query their capabilities.
The OSGi specification already provides chapters describing how to deploy software on remote infrastructure, how to call remote services or how manage a remote OSGi framework. In this chapter we define an API for a management agent to discover, list and inspect available nodes in the cluster.
-
Cluster - A cluster is a collection of nodes connected by a network. Most often the nodes are managed by a public or private cloud provider.
-
Node - A node is a discoverable entity in the cluster, for example a physical machine, a virtual machine (VM), a container or an OSGi framework.
-
NodeStatus - The Node Status service represents a node in the cluster. This can be any entity in the cluster such as a database server, a virtual machine, a container, an OSGi framework, etc.
-
FrameworkNodeStatus - The Framework Node Status service represents an OSGi framework in the cluster.
-
FrameworkManager - The FrameworkManager service provides an interface to manage an OSGi framework in the cluster.
We distinguish two types of nodes in a cluster. On the one hand we have OSGi frameworks, which publish their presence using a Framework Node Status service. On the other hand there can be other nodes in the cluster, such as the virtual machines or containers the OSGi frameworks are running on, or an external server such as a database. These can be represented using a Node Status service.
When an OSGi framework is part of a cluster, this means it gets access to remote services of any other OSGi framework in that cluster. Ensuring the discovery, visibility and access of remote services within the cluster is the responsibility of the Remote Service Admin Service Specification.
An example cluster deployment is shown in Figure 148.2 on page . Here, a cluster consisting of three virtual machines or containers has deployed a total of four OSGi frameworks. Each OSGi framework has a Cluster Information implementation running that exposes a Framework Node Status service. Besides these, there can also be an entity managing the virtual machines/containers (for example, the cloud provider), that exposes three Node Status services, one for each VM/container. In this case, each Framework Node Status will have a parent id pointing to the id of the Node Status of the VM/container it is deployed on.
The NodeStatus service advertises the availability of a node in the cluster. This node can be any entity in the cluster such as a physical machine, a virtual machine, a container or an OSGi framework.
The Node Status service provides metadata about the node via its service properties. Each Node Status must provide an id and cluster name. Optionally additional service properties can be provided such as the physical location of the node, the endpoints at which this node can be accessed, etc. These service properties can be converted to a NodeStatusDTO to have type-safe access to these properties using the Converter Specification.
Table 148.1 Service properties of the NodeStatus service
Service Property Name | Type | Description |
---|---|---|
osgi.clusterinfo.id |
String |
The globally unique ID for this node. For example the Docker ID if this node is a Docker container, or the framework UUID if this node is an OSGi framework. |
osgi.clusterinfo.cluster |
String |
The name of the cluster this node belongs to. |
osgi.clusterinfo.parent |
String |
In the case this node is part of or embedded in another node, this field contains the id of the parent node. For example multiple virtual machines could run on the same physical node. |
osgi.clusterinfo.endpoint |
String+ |
The endpoint(s) at which this node can be accessed from the viewpoint of the consumer of the service. |
osgi.clusterinfo.endpoint.private |
String+ |
Private endpoint(s) at which this node can be accessed from within the cluster only. |
osgi.clusterinfo.vendor |
String |
The vendor name of the cloud/environment in which the node operates. |
osgi.clusterinfo.version |
String |
The version of the cloud/environment in which the node operates. The value follows the versioning scheme of the cloud provider and may therefore not comply with the OSGi versioning syntax. |
osgi.clusterinfo.country |
String |
ISO 3166-1 alpha-3 location where this node is running, if known. |
osgi.clusterinfo.location |
String |
ISO 3166-2 location where this node is running, if known. This location is more detailed than the country code as it may contain province or territory. |
osgi.clusterinfo.region |
String |
Something smaller than a country and bigger than a location (for example, us-east-1 or other cloud-specific location) |
osgi.clusterinfo.zone |
String |
Regions are often subdivided in zones that represent different physical locations. The zone can be provided here. |
osgi.clusterinfo.tags |
String+ |
Tags associated with this node that can be contributed to by the provider and also by bundles. |
The Node Status service can also provide access to some dynamic
properties of the node. The getMetrics
method allows to query
key-value pairs, that are specific for that node. For example, for an OSGi
framework these could be CPU and memory usage, for a database node these
could be the number of database reads and writes, and for a VM these could
be metrics made accessible by the cloud provider. In this case the service
implementor can provide DTOs to have a type-safe way to access these
metrics by converting the returned map to one of these DTOs. For example,
an implementation could expose JMX metrics together with a type-safe
DTO:
public class JMXMetricsDTO extends DTO {
/**
* The number of processors available
*/
public int availableProcessors;
/**
* The average system load
*/
public float systemLoadAverage;
/**
* The maximal amount of heap memory available to the JVM
*/
public long heapMemoryMax;
/**
* The amount of heap memory used by the JVM
*/
public long heapMemoryUsed;
/**
* The maximal amount of non-heap memory available to the JVM
*/
public long nonHeapMemoryMax;
/**
* The amount of non-heap memory used by the JVM
*/
public long nonHeapMemoryUsed;
}
Such DTO can be used to obtain metrics from a
NodeStatus
service as follows:
// From service registry
NodeStatus ns = ...;
// Obtain all metrics for this node
Map<String, Object> metrics = ns.getMetrics();
// Convert the metrics map to a DTO for type-safe access
JMXMetricsDTO dto = Converters.standardConverter().convert(metrics)
.to(JMXMetricsDTO.class);
// Use metrics
System.out.println("System Load Average: " + dto.systemLoadAverage);
In case the cluster node is an OSGi framework, the FrameworkNodeStatus service is used to represent the node.
FrameworkNodeStatus
extends NodeStatus
, and the
node id is the OSGi framework UUID. Next to the Node Status service
properties, this service has some additional service properties describing
the OSGi and Java runtime:
Table 148.2 Additional service properties of the FrameworkNodeStatus service
Service Property Name | Type | Description |
---|---|---|
org.osgi.framework.version |
String |
The OSGi framework version. |
org.osgi.framework.processor |
String |
The OSGi framework processor architecture. |
org.osgi.framework.os_name |
String |
The OSGi framework operating system name. |
java.version |
String |
The Java version. |
java.runtime.version |
String |
The Java runtime version. |
java.specification.version |
String |
The Java specification version. |
java.vm.version |
String |
The Java VM version. |
Similar to the Node Status service, the service properties of the Framework Node Status service can be converted to a FrameworkNodeStatusDTO to have type-safe access to these properties using the Converter Specification.
The Framework Node Status service also extends the FrameworkManager interface, which provides a management interface for the OSGi framework. This allows a remote management agent to interact with the OSGi framework. The Framework Node Status service can be exported remotely with Remote Services, however alternative mechanisms to distribute this service are also permitted. For example, the FrameworkManager interface can also be made available through the REST Management Service Specification.
The following example uses the NodeStatus
properties
from a FrameworkNodeStatus
service to see what country the
framework is running in. If it is running in Germany a bundle specific for
that country is installed:
@Component
public class FrameworkProvisioner {
private static final Converter CONVERTER = Converters.standardConverter();
@Reference(cardinality = MULTIPLE, policy = DYNAMIC)
void addFramework(FrameworkNodeStatus fns, Map<String,Object> props) {
// Convert the properties to the DTO for type safe access
NodeStatusDTO dto = CONVERTER.convert(props).to(NodeStatusDTO.class);
// Check the ISO 3166-1 alpha 3 country code
if ("DEU".equals(dto.country)) {
// If this framework runs in Germany, install a special bundle into it
try {
fns.installBundle("... Germany specific bundle ...");
} catch (Exception e) {
// log
}
}
}
}
The Node Status service provides a
osgi.clusterinfo.tags
property. Here, application specific
tags can be assigned to the NodeStatus
services. For example,
one could assign different roles to the nodes such as "worker",
"database", "storage", "gateway", etc. These roles are
application-specific and should be defined by the application
developer.
Bundles can specify additional tags to be included in the
FrameworkNodeStatus
service representing the current
framework by registering any service with the service property
org.osgi.service.clusterinfo.tags
providing a custom
String[]
of tags. The Cluster Information implementation will
add those to the tags property of the FrameworkNodeStatus
service that represents the OSGi framework. For example:
// Register an arbitrary service that communicates the tags
// to be added to the osgi.clusterinfo.tags service property.
Dictionary<String, Object> props = new Hashtable<>();
props.put("org.osgi.service.clusterinfo.tags",
new String [] {"database", "large_box"});
bundleContext.registerService(MyClass.class, this, props);
The ClusterTagPermission
class allows fine-grained
control over which bundles may add which tags to the Framework Node
Status service. A bundle can be granted to add a certain tag to the
Framework Node Status, or be granted to add any tag using the *
wildcard.
The Cluster Information Specification should only be implemented
by trusted bundles. These bundles require
ServicePermission[NodeStatus|FrameworkNodeStatus|FrameworkManager,
REGISTER]
.
All bundles accessing the Cluster Information services should get
ServicePermission[NodeStatus|FrameworkNodeStatus|FrameworkManager,
GET]
.
Only trusted bundles who must be able to add Node Status tags
should be assigned ClusterTagPermission[ClusterTag,
ADD]
.
By default, all remote OSGi services are visible within a cluster. This is handled by the Remote Service Admin Service Specification.
ClusterInfo Services Package Version 1.0.
Bundles wishing to use this package must list the package in the Import-Package header of the bundle's manifest. This package has two types of users: the consumers that use the API in this package and the providers that implement the API in this package.
Example import for consumers using the API in this package:
Import-Package: org.osgi.service.clusterinfo; version="[1.0,2.0)"
Example import for providers implementing the API in this package:
Import-Package: org.osgi.service.clusterinfo; version="[1.0,1.1)"
-
ClusterTagPermission
- A bundle's authority to add a tag to a NodeStatus service. -
FrameworkManager
- Provides a management interface for accessing and managing a remote OSGi framework. -
FrameworkNodeStatus
- The FrameworkNodeStatus service represents a node in the cluster that is also an OSGi framework. -
NodeStatus
- The NodeStatus service represents a node in the cluster.
A bundle's authority to add a tag to a NodeStatus service.
Give permission to add this tag, use * wildcard to give permission to add any tag.
add
.
Defines the authority to add a tag to the NodeStatus service.
The object to test for equality with this
ClusterTagPermission
object.
Determines the equality of two ClusterTagPermission
objects. This
method checks that specified ClusterTagPermission
has the same
tag as this ClusterTagPermission
object.
true
if obj
is a ClusterTagPermission
,
and has the same tag as this ClusterTagPermission
object;
false
otherwise.
Returns the canonical string representation of the
ClusterTagPermission
action.
Always returns the ADD action.
Canonical string representation of the
ClusterTagPermission
actions.
Returns the hash code value for this object.
A hash code value for this object.
The target permission to interrogate.
Determines if the specified permission is implied by this object.
This method checks that the tag of the target is implied by the tag name of this object.
true
if the specified ClusterTagPermission
action
is implied by this object; false
otherwise.
Provides a management interface for accessing and managing a remote OSGi framework. This interface can be accessed remotely via Remote Services.
Addresses the bundle by its identifier.
Retrieve the bundle representation for a given bundle Id.
A BundleDTO for the requested bundle.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
Get the header for a bundle given by its bundle Id.
Returns the map of headers entries.
Exception
– An exception representing a failure in the underlying
remote call.
Get the bundle representations for all bundles currently installed in the managed framework.
Returns a collection of BundleDTO objects.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
Get the start level for a bundle given by its bundle Id.
Returns a BundleStartLevelDTO describing the current start level of the bundle.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
Get the state for a given bundle Id.
Returns the current bundle state as defined in org.osgi.framework.Bundle.
Exception
– An exception representing a failure in the underlying
remote call.
Retrieves the current framework start level.
Returns the current framework start level in the form of a FrameworkStartLevelDTO.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the service by its identifier.
Get the service representation for a service given by its service Id.
The service representation as ServiceReferenceDTO.
Exception
– An exception representing a failure in the underlying
remote call.
Get the service representations for all services.
Returns the service representations in the form of ServiceReferenceDTO objects.
Exception
– An exception representing a failure in the underlying
remote call.
Passes a filter to restrict the result set.
Get the service representations for all services.
Returns the service representations in the form of ServiceReferenceDTO objects.
Exception
– An exception representing a failure in the underlying
remote call.
Passes the location string to retrieve the bundle content from.
Install a new bundle given by an externally reachable location string, typically describing a URL.
Returns the BundleDTO of the newly installed bundle.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
The target start level.
Set the start level for a bundle given by its bundle Id.
Exception
– An exception representing a failure in the underlying
remote call.
set the framework start level to this target.
Sets the current framework start level.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
Start a bundle given by its bundle Id.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
Passes additional options as defined in org.osgi.framework.Bundle.start(int)
Start a bundle given by its bundle Id.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
Stop a bundle given by its bundle Id.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
Passes additional options as defined in org.osgi.framework.Bundle.stop(int)
Stop a bundle given by its bundle Id.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
Uninstall a bundle given by its bundle Id.
Returns the BundleDTO of the uninstalled bundle.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
Updates a bundle given by its bundle Id using the bundle-internal update location.
Returns the BundleDTO of the updated bundle.
Exception
– An exception representing a failure in the underlying
remote call.
Addresses the bundle by its identifier.
The URL whose content is to be used to update the bundle.
Updates a bundle given by its URI path using the content at the specified URL.
Returns the BundleDTO of the updated bundle.
Exception
– An exception representing a failure in the underlying
remote call.
The FrameworkNodeStatus service represents a node in the cluster that is also an OSGi framework.
The NodeStatus service represents a node in the cluster.
A node could represent an entity available in the network that is not necessarily running an OSGi framework, such as a database or a load balancer.
a set of metric names that have to be obtained from the node. Of no names are specified all available metrics will be obtained. If a metric is requested that is not available by the node this metric is ignored and not present in the returned map.
Get the current metrics or other dynamic data from the node. Nodes may support custom metrics and as such the caller can request those metrics by name. The caller can specify the metric names to avoid having to compute and send all metrics over, if the caller is only interested in a subset of the available metrics.
Map with the current node metrics
ClusterInfo DTO Package Version 1.0.
Bundles wishing to use this package must list the package in the Import-Package header of the bundle's manifest. This package has two types of users: the consumers that use the API in this package and the providers that implement the API in this package.
Example import for consumers using the API in this package:
Import-Package: org.osgi.service.clusterinfo.dto; version="[1.0,2.0)"
Example import for providers implementing the API in this package:
Import-Package: org.osgi.service.clusterinfo.dto; version="[1.0,1.1)"
-
FrameworkNodeStatusDTO
- Data Transfer Object for a FrameworkNodeStatus Service. -
NodeStatusDTO
- Data Transfer Object for a NodeStatus Service.
Data Transfer Object for a FrameworkNodeStatus Service.
This DTO can be used to provide type safe access to properties of the FrameworkNodeStatus service.
Data Transfer Object for a NodeStatus Service.
ISO 3166-1 alpha-3 location where this node instance is running, if known.
The endpoint(s) at which this node can be accessed from the viewpoint of the consumer of the service.
The globally unique ID for this node. For example the Docker ID if this node is a Docker container, or the framework UUID if this node is an OSGi framework.
ISO 3166-2 location where this node instance is running, if known. This location is more detailed than the country code as it may contain province or territory.
An optional parentID indicating this node is part of or embedded in another node. For example multiple virtual machines could run on the same physical node.
Private endpoint(s) at which this node can be accessed from within the cluster only.
Something smaller than a country and bigger than a location (e.g. us-east-1 or other cloud-specific location)
Tags associated with this node that can be contributed to by the provider and also by bundles.
The vendor name of the cloud/environment in which the node operates.
The version of the cloud/environment in which the node operates. The value follows the versioning scheme of the cloud provider and may therefore not comply with the OSGi versioning syntax.
Regions are often subdivided in zones that represent different physical locations. The zone can be provided here.
This DTO can be used to provide type safe access to properties of the NodeStatus service.