Skip to content
Snippets Groups Projects
Commit 2c26a307 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Merge branch 'feat/138-ubi-error-handling-in-ztp-component-3' into 'develop'

Resolve "(UBI) Error handling in ZTP component"

See merge request !228
parents 265a2f46 8613c5a5
No related branches found
No related tags found
2 merge requests!235Release TeraFlowSDN 3.0,!228Resolve "(UBI) Error handling in ZTP component"
Showing
with 7839 additions and 220 deletions
......@@ -23,12 +23,12 @@ import org.etsi.tfs.ztp.context.ContextService;
import org.etsi.tfs.ztp.context.model.Device;
import org.etsi.tfs.ztp.context.model.DeviceConfig;
import org.etsi.tfs.ztp.device.DeviceService;
import org.etsi.tfs.ztp.exception.ExternalServiceFailureException;
import org.jboss.logging.Logger;
@ApplicationScoped
public class ZtpServiceImpl implements ZtpService {
private static final Logger LOGGER = Logger.getLogger(ZtpServiceImpl.class);
// private static final String MESSAGE = "Retrieved %s";
private final DeviceService deviceService;
private final ContextService contextService;
......@@ -41,128 +41,104 @@ public class ZtpServiceImpl implements ZtpService {
@Override
public Uni<Device> addDevice(String deviceId) {
final var deserializedDeviceUni = contextService.getDevice(deviceId);
deserializedDeviceUni
return contextService
.getDevice(deviceId)
.onFailure()
.recoverWithNull()
.subscribe()
.with(
.transform(failure -> new ExternalServiceFailureException(failure.getMessage()))
.onItem()
.transformToUni(
device -> {
final var id = deviceId;
if (device == null) {
LOGGER.warnf("%s is null. Ignoring...", device);
return;
}
if (device.isEnabled()) {
LOGGER.warnf("%s has already been enabled. Ignoring...", device);
return;
return Uni.createFrom().failure(new Exception("Device is already enabled"));
} else {
return addDeviceTo(device, deviceId);
}
});
}
// LOGGER.infof(MESSAGE, device);
final var initialConfiguration =
deviceService.getInitialConfiguration(device.getDeviceId());
device.enableDevice();
LOGGER.infof("Enabled device [%s]", id);
public Uni<Device> addDeviceTo(Device device, String deviceId) {
LOGGER.infof("Enabling device with ID [%s]", deviceId);
device.enableDevice();
initialConfiguration
.subscribe()
.with(
deviceConfig -> {
device.setDeviceConfiguration(deviceConfig);
final var configuredDeviceIdUni = deviceService.configureDevice(device);
final Uni<DeviceConfig> initialConfiguration = deviceService.getInitialConfiguration(deviceId);
configuredDeviceIdUni
.subscribe()
.with(
configuredDeviceId ->
LOGGER.infof(
"Device [%s] has been successfully enabled and configured with %s.\n",
id, deviceConfig));
return initialConfiguration
.onItem()
.transformToUni(
deviceConfig -> {
device.setDeviceConfiguration(deviceConfig);
LOGGER.infof(
"Configuring device with ID [%s] with initial configuration %s",
deviceId, deviceConfig);
return deviceService
.configureDevice(device)
.map(
configuredDeviceId -> {
LOGGER.infof(
"Device with ID [%s] has been successfully enabled and configured.",
deviceId);
return device;
});
});
return deserializedDeviceUni;
}
@Override
public Uni<Device> deleteDevice(String deviceId) {
final var deserializedDeviceUni = contextService.getDevice(deviceId);
deserializedDeviceUni
return contextService
.getDevice(deviceId)
.onFailure()
.recoverWithNull()
.subscribe()
.with(
.transform(failure -> new ExternalServiceFailureException(failure.getMessage()))
.onItem()
.transformToUni(
device -> {
final var id = deviceId;
if (device == null) {
LOGGER.warnf("%s is null. Ignoring...", device);
return;
}
if (device.isDisabled()) {
LOGGER.warnf("%s has already been disabled. Ignoring...", device);
return;
LOGGER.warnf("Device with ID %s has already been disabled. Ignoring...", deviceId);
return Uni.createFrom().nullItem();
} else {
LOGGER.infof("Disabling device with ID [%s]", deviceId);
device.disableDevice();
return deviceService
.deleteDevice(deviceId)
.onItem()
.transform(
emptyMessage -> {
LOGGER.infof(
"Device with ID [%s] has been successfully deleted.", deviceId);
return device;
});
}
device.disableDevice();
LOGGER.infof("Disabled device [%s]", id);
// LOGGER.infof(MESSAGE, device);
final var empty = deviceService.deleteDevice(device.getDeviceId());
empty
.subscribe()
.with(
emptyMessage ->
LOGGER.infof("Device [%s] has been successfully deleted.\n", id));
});
return deserializedDeviceUni;
}
@Override
public Uni<Device> updateDevice(String deviceId, DeviceConfig deviceConfig) {
final var deserializedDeviceUni = contextService.getDevice(deviceId);
deserializedDeviceUni
return contextService
.getDevice(deviceId)
.onFailure()
.recoverWithNull()
.subscribe()
.with(
.transform(failure -> new ExternalServiceFailureException(failure.getMessage()))
.onItem()
.transformToUni(
device -> {
final var id = deviceId;
if (device == null) {
LOGGER.warnf("%s is null. Ignoring...", device);
return;
}
if (!device.isEnabled()) {
LOGGER.warnf("Cannot update disabled device %s. Ignoring...", device);
return;
}
// LOGGER.infof(MESSAGE, device);
device.setDeviceConfiguration(deviceConfig);
final var updatedDeviceIdUni = deviceService.configureDevice(device);
updatedDeviceIdUni
.subscribe()
.with(
configuredDeviceId ->
LOGGER.warnf("Cannot update disabled device %s. Ignoring...", deviceId);
return Uni.createFrom().nullItem();
} else {
LOGGER.infof("Updating configuration of device with ID [%s]", deviceId);
device.setDeviceConfiguration(deviceConfig);
return deviceService
.configureDevice(device)
.onItem()
.transform(
configuredDeviceId -> {
LOGGER.infof(
"Device [%s] has been successfully updated with %s.\n",
id, deviceConfig));
"Device with ID [%s] has been successfully updated with %s.",
deviceId, deviceConfig);
return device;
});
}
});
return deserializedDeviceUni;
}
}
/*
* Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.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.etsi.tfs.ztp.exception;
public class ExternalServiceFailureException extends RuntimeException {
public ExternalServiceFailureException(String message, Exception e) {
super(message, e);
}
public ExternalServiceFailureException(String message) {
super(message);
}
}
/*
* Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.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.etsi.tfs.ztp.exception;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.quarkus.grpc.ExceptionHandlerProvider;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class GeneralExceptionHandler implements ExceptionHandlerProvider {
@Override
public <ReqT, RespT> io.quarkus.grpc.ExceptionHandler<ReqT, RespT> createHandler(
ServerCall.Listener<ReqT> listener, ServerCall<ReqT, RespT> serverCall, Metadata metadata) {
return new HelloExceptionHandler<>(listener, serverCall, metadata);
}
@Override
public Throwable transform(Throwable t) {
if (t instanceof ExternalServiceFailureException) {
return new StatusRuntimeException(Status.INTERNAL.withDescription(t.getMessage()));
} else {
return ExceptionHandlerProvider.toStatusException(t, true);
}
}
private static class HelloExceptionHandler<A, B> extends io.quarkus.grpc.ExceptionHandler<A, B> {
public HelloExceptionHandler(
ServerCall.Listener<A> listener, ServerCall<A, B> call, Metadata metadata) {
super(listener, call, metadata);
}
@Override
protected void handleException(Throwable t, ServerCall<A, B> call, Metadata metadata) {
StatusRuntimeException sre =
(StatusRuntimeException) ExceptionHandlerProvider.toStatusException(t, true);
Metadata trailers = sre.getTrailers() != null ? sre.getTrailers() : metadata;
call.close(sre.getStatus(), trailers);
}
}
}
......@@ -15,6 +15,11 @@
ztp:
should-subscribe-to-context-component: true
quarkus:
package:
type: mutable-jar
live-reload:
password: 1234
url: http://0.0.0.0:8080
banner:
path: teraflow-ztp-banner.txt
grpc:
......
......@@ -89,6 +89,23 @@ public interface ContextService extends MutinyService {
io.smallrye.mutiny.Uni<context.ContextOuterClass.Empty> removeConnection(context.ContextOuterClass.ConnectionId request);
/**
* <pre>
* ------------------------------ Experimental -----------------------------
* </pre>
*/
io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalConfigList> getOpticalConfig(context.ContextOuterClass.Empty request);
io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalConfigId> setOpticalConfig(context.ContextOuterClass.OpticalConfig request);
io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalConfig> selectOpticalConfig(context.ContextOuterClass.OpticalConfigId request);
io.smallrye.mutiny.Uni<context.ContextOuterClass.Empty> setOpticalLink(context.ContextOuterClass.OpticalLink request);
io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalLink> getOpticalLink(context.ContextOuterClass.OpticalLinkId request);
io.smallrye.mutiny.Uni<context.ContextOuterClass.Fiber> getFiber(context.ContextOuterClass.FiberId request);
io.smallrye.mutiny.Multi<context.ContextOuterClass.ContextEvent> getContextEvents(context.ContextOuterClass.Empty request);
io.smallrye.mutiny.Multi<context.ContextOuterClass.TopologyEvent> getTopologyEvents(context.ContextOuterClass.Empty request);
......
......@@ -391,6 +391,60 @@ public class ContextServiceBean extends MutinyContextServiceGrpc.ContextServiceI
}
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalConfigList> getOpticalConfig(context.ContextOuterClass.Empty request) {
try {
return delegate.getOpticalConfig(request);
} catch (UnsupportedOperationException e) {
throw new io.grpc.StatusRuntimeException(io.grpc.Status.UNIMPLEMENTED);
}
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalConfigId> setOpticalConfig(context.ContextOuterClass.OpticalConfig request) {
try {
return delegate.setOpticalConfig(request);
} catch (UnsupportedOperationException e) {
throw new io.grpc.StatusRuntimeException(io.grpc.Status.UNIMPLEMENTED);
}
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalConfig> selectOpticalConfig(context.ContextOuterClass.OpticalConfigId request) {
try {
return delegate.selectOpticalConfig(request);
} catch (UnsupportedOperationException e) {
throw new io.grpc.StatusRuntimeException(io.grpc.Status.UNIMPLEMENTED);
}
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.Empty> setOpticalLink(context.ContextOuterClass.OpticalLink request) {
try {
return delegate.setOpticalLink(request);
} catch (UnsupportedOperationException e) {
throw new io.grpc.StatusRuntimeException(io.grpc.Status.UNIMPLEMENTED);
}
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalLink> getOpticalLink(context.ContextOuterClass.OpticalLinkId request) {
try {
return delegate.getOpticalLink(request);
} catch (UnsupportedOperationException e) {
throw new io.grpc.StatusRuntimeException(io.grpc.Status.UNIMPLEMENTED);
}
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.Fiber> getFiber(context.ContextOuterClass.FiberId request) {
try {
return delegate.getFiber(request);
} catch (UnsupportedOperationException e) {
throw new io.grpc.StatusRuntimeException(io.grpc.Status.UNIMPLEMENTED);
}
}
@Override
public io.smallrye.mutiny.Multi<context.ContextOuterClass.ContextEvent> getContextEvents(context.ContextOuterClass.Empty request) {
try {
......
......@@ -235,6 +235,36 @@ public class ContextServiceClient implements ContextService, MutinyClient<Mutiny
return stub.removeConnection(request);
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalConfigList> getOpticalConfig(context.ContextOuterClass.Empty request) {
return stub.getOpticalConfig(request);
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalConfigId> setOpticalConfig(context.ContextOuterClass.OpticalConfig request) {
return stub.setOpticalConfig(request);
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalConfig> selectOpticalConfig(context.ContextOuterClass.OpticalConfigId request) {
return stub.selectOpticalConfig(request);
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.Empty> setOpticalLink(context.ContextOuterClass.OpticalLink request) {
return stub.setOpticalLink(request);
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.OpticalLink> getOpticalLink(context.ContextOuterClass.OpticalLinkId request) {
return stub.getOpticalLink(request);
}
@Override
public io.smallrye.mutiny.Uni<context.ContextOuterClass.Fiber> getFiber(context.ContextOuterClass.FiberId request) {
return stub.getFiber(request);
}
@Override
public io.smallrye.mutiny.Multi<context.ContextOuterClass.ContextEvent> getContextEvents(context.ContextOuterClass.Empty request) {
return stub.getContextEvents(request);
......
......@@ -3,8 +3,8 @@ apiVersion: v1
kind: Service
metadata:
annotations:
app.quarkus.io/commit-id: 9fcc34bb0e7806d8a5ca5f75cbf3cb9e3358d756
app.quarkus.io/build-timestamp: 2024-02-15 - 11:02:55 +0000
app.quarkus.io/commit-id: 7fce72764fa6bb9b37b407bbcba502cc0a23735f
app.quarkus.io/build-timestamp: 2024-04-04 - 09:35:22 +0000
prometheus.io/scrape: "true"
prometheus.io/path: /q/metrics
prometheus.io/port: "8080"
......@@ -17,18 +17,18 @@ metadata:
name: ztpservice
spec:
ports:
- name: https
port: 443
- name: http
port: 9192
protocol: TCP
targetPort: 8443
targetPort: 8080
- name: grpc
port: 5050
protocol: TCP
targetPort: 5050
- name: http
port: 9192
- name: https
port: 443
protocol: TCP
targetPort: 8080
targetPort: 8443
selector:
app.kubernetes.io/name: ztpservice
type: ClusterIP
......@@ -37,8 +37,8 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
app.quarkus.io/commit-id: 9fcc34bb0e7806d8a5ca5f75cbf3cb9e3358d756
app.quarkus.io/build-timestamp: 2024-02-15 - 11:02:55 +0000
app.quarkus.io/commit-id: 7fce72764fa6bb9b37b407bbcba502cc0a23735f
app.quarkus.io/build-timestamp: 2024-04-04 - 09:35:22 +0000
prometheus.io/scrape: "true"
prometheus.io/path: /q/metrics
prometheus.io/port: "8080"
......@@ -46,8 +46,8 @@ metadata:
labels:
app: ztpservice
app.kubernetes.io/managed-by: quarkus
app.kubernetes.io/version: 0.2.0
app.kubernetes.io/name: ztpservice
app.kubernetes.io/version: 0.2.0
name: ztpservice
spec:
replicas: 1
......@@ -57,8 +57,8 @@ spec:
template:
metadata:
annotations:
app.quarkus.io/commit-id: 9fcc34bb0e7806d8a5ca5f75cbf3cb9e3358d756
app.quarkus.io/build-timestamp: 2024-02-15 - 11:02:55 +0000
app.quarkus.io/commit-id: 7fce72764fa6bb9b37b407bbcba502cc0a23735f
app.quarkus.io/build-timestamp: 2024-04-04 - 09:35:22 +0000
prometheus.io/scrape: "true"
prometheus.io/path: /q/metrics
prometheus.io/port: "8080"
......@@ -66,8 +66,8 @@ spec:
labels:
app: ztpservice
app.kubernetes.io/managed-by: quarkus
app.kubernetes.io/version: 0.2.0
app.kubernetes.io/name: ztpservice
app.kubernetes.io/version: 0.2.0
spec:
containers:
- env:
......@@ -75,10 +75,10 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CONTEXT_SERVICE_HOST
value: contextservice
- name: DEVICE_SERVICE_HOST
value: deviceservice
- name: CONTEXT_SERVICE_HOST
value: contextservice
image: labs.etsi.org:5050/tfs/controller/ztp:0.2.0
imagePullPolicy: Always
livenessProbe:
......@@ -93,14 +93,14 @@ spec:
timeoutSeconds: 10
name: ztpservice
ports:
- containerPort: 8443
name: https
- containerPort: 8080
name: http
protocol: TCP
- containerPort: 5050
name: grpc
protocol: TCP
- containerPort: 8080
name: http
- containerPort: 8443
name: https
protocol: TCP
readinessProbe:
failureThreshold: 3
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment