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; ...@@ -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.Device;
import org.etsi.tfs.ztp.context.model.DeviceConfig; import org.etsi.tfs.ztp.context.model.DeviceConfig;
import org.etsi.tfs.ztp.device.DeviceService; import org.etsi.tfs.ztp.device.DeviceService;
import org.etsi.tfs.ztp.exception.ExternalServiceFailureException;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ApplicationScoped @ApplicationScoped
public class ZtpServiceImpl implements ZtpService { public class ZtpServiceImpl implements ZtpService {
private static final Logger LOGGER = Logger.getLogger(ZtpServiceImpl.class); private static final Logger LOGGER = Logger.getLogger(ZtpServiceImpl.class);
// private static final String MESSAGE = "Retrieved %s";
private final DeviceService deviceService; private final DeviceService deviceService;
private final ContextService contextService; private final ContextService contextService;
...@@ -41,128 +41,104 @@ public class ZtpServiceImpl implements ZtpService { ...@@ -41,128 +41,104 @@ public class ZtpServiceImpl implements ZtpService {
@Override @Override
public Uni<Device> addDevice(String deviceId) { public Uni<Device> addDevice(String deviceId) {
final var deserializedDeviceUni = contextService.getDevice(deviceId); return contextService
.getDevice(deviceId)
deserializedDeviceUni
.onFailure() .onFailure()
.recoverWithNull() .transform(failure -> new ExternalServiceFailureException(failure.getMessage()))
.subscribe() .onItem()
.with( .transformToUni(
device -> { device -> {
final var id = deviceId;
if (device == null) {
LOGGER.warnf("%s is null. Ignoring...", device);
return;
}
if (device.isEnabled()) { if (device.isEnabled()) {
LOGGER.warnf("%s has already been enabled. Ignoring...", device); 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); public Uni<Device> addDeviceTo(Device device, String deviceId) {
LOGGER.infof("Enabling device with ID [%s]", deviceId);
final var initialConfiguration = device.enableDevice();
deviceService.getInitialConfiguration(device.getDeviceId());
device.enableDevice();
LOGGER.infof("Enabled device [%s]", id);
initialConfiguration final Uni<DeviceConfig> initialConfiguration = deviceService.getInitialConfiguration(deviceId);
.subscribe()
.with(
deviceConfig -> {
device.setDeviceConfiguration(deviceConfig);
final var configuredDeviceIdUni = deviceService.configureDevice(device);
configuredDeviceIdUni return initialConfiguration
.subscribe() .onItem()
.with( .transformToUni(
configuredDeviceId -> deviceConfig -> {
LOGGER.infof( device.setDeviceConfiguration(deviceConfig);
"Device [%s] has been successfully enabled and configured with %s.\n", LOGGER.infof(
id, deviceConfig)); "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 @Override
public Uni<Device> deleteDevice(String deviceId) { public Uni<Device> deleteDevice(String deviceId) {
final var deserializedDeviceUni = contextService.getDevice(deviceId); return contextService
.getDevice(deviceId)
deserializedDeviceUni
.onFailure() .onFailure()
.recoverWithNull() .transform(failure -> new ExternalServiceFailureException(failure.getMessage()))
.subscribe() .onItem()
.with( .transformToUni(
device -> { device -> {
final var id = deviceId;
if (device == null) {
LOGGER.warnf("%s is null. Ignoring...", device);
return;
}
if (device.isDisabled()) { if (device.isDisabled()) {
LOGGER.warnf("%s has already been disabled. Ignoring...", device); LOGGER.warnf("Device with ID %s has already been disabled. Ignoring...", deviceId);
return; 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 @Override
public Uni<Device> updateDevice(String deviceId, DeviceConfig deviceConfig) { public Uni<Device> updateDevice(String deviceId, DeviceConfig deviceConfig) {
final var deserializedDeviceUni = contextService.getDevice(deviceId); return contextService
.getDevice(deviceId)
deserializedDeviceUni
.onFailure() .onFailure()
.recoverWithNull() .transform(failure -> new ExternalServiceFailureException(failure.getMessage()))
.subscribe() .onItem()
.with( .transformToUni(
device -> { device -> {
final var id = deviceId;
if (device == null) {
LOGGER.warnf("%s is null. Ignoring...", device);
return;
}
if (!device.isEnabled()) { if (!device.isEnabled()) {
LOGGER.warnf("Cannot update disabled device %s. Ignoring...", device); LOGGER.warnf("Cannot update disabled device %s. Ignoring...", deviceId);
return; return Uni.createFrom().nullItem();
} } else {
LOGGER.infof("Updating configuration of device with ID [%s]", deviceId);
// LOGGER.infof(MESSAGE, device); device.setDeviceConfiguration(deviceConfig);
device.setDeviceConfiguration(deviceConfig);
final var updatedDeviceIdUni = deviceService.configureDevice(device); return deviceService
.configureDevice(device)
updatedDeviceIdUni .onItem()
.subscribe() .transform(
.with( configuredDeviceId -> {
configuredDeviceId ->
LOGGER.infof( LOGGER.infof(
"Device [%s] has been successfully updated with %s.\n", "Device with ID [%s] has been successfully updated with %s.",
id, deviceConfig)); 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 @@ ...@@ -15,6 +15,11 @@
ztp: ztp:
should-subscribe-to-context-component: true should-subscribe-to-context-component: true
quarkus: quarkus:
package:
type: mutable-jar
live-reload:
password: 1234
url: http://0.0.0.0:8080
banner: banner:
path: teraflow-ztp-banner.txt path: teraflow-ztp-banner.txt
grpc: grpc:
......
...@@ -89,6 +89,23 @@ public interface ContextService extends MutinyService { ...@@ -89,6 +89,23 @@ public interface ContextService extends MutinyService {
io.smallrye.mutiny.Uni<context.ContextOuterClass.Empty> removeConnection(context.ContextOuterClass.ConnectionId request); 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.ContextEvent> getContextEvents(context.ContextOuterClass.Empty request);
io.smallrye.mutiny.Multi<context.ContextOuterClass.TopologyEvent> getTopologyEvents(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 ...@@ -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 @Override
public io.smallrye.mutiny.Multi<context.ContextOuterClass.ContextEvent> getContextEvents(context.ContextOuterClass.Empty request) { public io.smallrye.mutiny.Multi<context.ContextOuterClass.ContextEvent> getContextEvents(context.ContextOuterClass.Empty request) {
try { try {
......
...@@ -235,6 +235,36 @@ public class ContextServiceClient implements ContextService, MutinyClient<Mutiny ...@@ -235,6 +235,36 @@ public class ContextServiceClient implements ContextService, MutinyClient<Mutiny
return stub.removeConnection(request); 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 @Override
public io.smallrye.mutiny.Multi<context.ContextOuterClass.ContextEvent> getContextEvents(context.ContextOuterClass.Empty request) { public io.smallrye.mutiny.Multi<context.ContextOuterClass.ContextEvent> getContextEvents(context.ContextOuterClass.Empty request) {
return stub.getContextEvents(request); return stub.getContextEvents(request);
......
...@@ -3,8 +3,8 @@ apiVersion: v1 ...@@ -3,8 +3,8 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
annotations: annotations:
app.quarkus.io/commit-id: 9fcc34bb0e7806d8a5ca5f75cbf3cb9e3358d756 app.quarkus.io/commit-id: 7fce72764fa6bb9b37b407bbcba502cc0a23735f
app.quarkus.io/build-timestamp: 2024-02-15 - 11:02:55 +0000 app.quarkus.io/build-timestamp: 2024-04-04 - 09:35:22 +0000
prometheus.io/scrape: "true" prometheus.io/scrape: "true"
prometheus.io/path: /q/metrics prometheus.io/path: /q/metrics
prometheus.io/port: "8080" prometheus.io/port: "8080"
...@@ -17,18 +17,18 @@ metadata: ...@@ -17,18 +17,18 @@ metadata:
name: ztpservice name: ztpservice
spec: spec:
ports: ports:
- name: https - name: http
port: 443 port: 9192
protocol: TCP protocol: TCP
targetPort: 8443 targetPort: 8080
- name: grpc - name: grpc
port: 5050 port: 5050
protocol: TCP protocol: TCP
targetPort: 5050 targetPort: 5050
- name: http - name: https
port: 9192 port: 443
protocol: TCP protocol: TCP
targetPort: 8080 targetPort: 8443
selector: selector:
app.kubernetes.io/name: ztpservice app.kubernetes.io/name: ztpservice
type: ClusterIP type: ClusterIP
...@@ -37,8 +37,8 @@ apiVersion: apps/v1 ...@@ -37,8 +37,8 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
annotations: annotations:
app.quarkus.io/commit-id: 9fcc34bb0e7806d8a5ca5f75cbf3cb9e3358d756 app.quarkus.io/commit-id: 7fce72764fa6bb9b37b407bbcba502cc0a23735f
app.quarkus.io/build-timestamp: 2024-02-15 - 11:02:55 +0000 app.quarkus.io/build-timestamp: 2024-04-04 - 09:35:22 +0000
prometheus.io/scrape: "true" prometheus.io/scrape: "true"
prometheus.io/path: /q/metrics prometheus.io/path: /q/metrics
prometheus.io/port: "8080" prometheus.io/port: "8080"
...@@ -46,8 +46,8 @@ metadata: ...@@ -46,8 +46,8 @@ metadata:
labels: labels:
app: ztpservice app: ztpservice
app.kubernetes.io/managed-by: quarkus app.kubernetes.io/managed-by: quarkus
app.kubernetes.io/version: 0.2.0
app.kubernetes.io/name: ztpservice app.kubernetes.io/name: ztpservice
app.kubernetes.io/version: 0.2.0
name: ztpservice name: ztpservice
spec: spec:
replicas: 1 replicas: 1
...@@ -57,8 +57,8 @@ spec: ...@@ -57,8 +57,8 @@ spec:
template: template:
metadata: metadata:
annotations: annotations:
app.quarkus.io/commit-id: 9fcc34bb0e7806d8a5ca5f75cbf3cb9e3358d756 app.quarkus.io/commit-id: 7fce72764fa6bb9b37b407bbcba502cc0a23735f
app.quarkus.io/build-timestamp: 2024-02-15 - 11:02:55 +0000 app.quarkus.io/build-timestamp: 2024-04-04 - 09:35:22 +0000
prometheus.io/scrape: "true" prometheus.io/scrape: "true"
prometheus.io/path: /q/metrics prometheus.io/path: /q/metrics
prometheus.io/port: "8080" prometheus.io/port: "8080"
...@@ -66,8 +66,8 @@ spec: ...@@ -66,8 +66,8 @@ spec:
labels: labels:
app: ztpservice app: ztpservice
app.kubernetes.io/managed-by: quarkus app.kubernetes.io/managed-by: quarkus
app.kubernetes.io/version: 0.2.0
app.kubernetes.io/name: ztpservice app.kubernetes.io/name: ztpservice
app.kubernetes.io/version: 0.2.0
spec: spec:
containers: containers:
- env: - env:
...@@ -75,10 +75,10 @@ spec: ...@@ -75,10 +75,10 @@ spec:
valueFrom: valueFrom:
fieldRef: fieldRef:
fieldPath: metadata.namespace fieldPath: metadata.namespace
- name: CONTEXT_SERVICE_HOST
value: contextservice
- name: DEVICE_SERVICE_HOST - name: DEVICE_SERVICE_HOST
value: deviceservice value: deviceservice
- name: CONTEXT_SERVICE_HOST
value: contextservice
image: labs.etsi.org:5050/tfs/controller/ztp:0.2.0 image: labs.etsi.org:5050/tfs/controller/ztp:0.2.0
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:
...@@ -93,14 +93,14 @@ spec: ...@@ -93,14 +93,14 @@ spec:
timeoutSeconds: 10 timeoutSeconds: 10
name: ztpservice name: ztpservice
ports: ports:
- containerPort: 8443 - containerPort: 8080
name: https name: http
protocol: TCP protocol: TCP
- containerPort: 5050 - containerPort: 5050
name: grpc name: grpc
protocol: TCP protocol: TCP
- containerPort: 8080 - containerPort: 8443
name: http name: https
protocol: TCP protocol: TCP
readinessProbe: readinessProbe:
failureThreshold: 3 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