All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.lighty.modules.gnmi.simulatordevice.impl.SimulatedGnmiDevice Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2021 PANTHEON.tech s.r.o. All Rights Reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at https://www.eclipse.org/legal/epl-v10.html
 */

package io.lighty.modules.gnmi.simulatordevice.impl;

import com.google.gson.Gson;
import gnmi.Gnmi;
import io.grpc.Server;
import io.grpc.netty.InternalProtocolNegotiators;
import io.grpc.netty.NettyServerBuilder;
import io.lighty.modules.gnmi.simulatordevice.config.GnmiSimulatorConfiguration;
import io.lighty.modules.gnmi.simulatordevice.gnmi.AuthenticationInterceptor;
import io.lighty.modules.gnmi.simulatordevice.gnmi.GnmiService;
import io.lighty.modules.gnmi.simulatordevice.gnoi.GnoiCertService;
import io.lighty.modules.gnmi.simulatordevice.gnoi.GnoiFileService;
import io.lighty.modules.gnmi.simulatordevice.gnoi.GnoiOSService;
import io.lighty.modules.gnmi.simulatordevice.gnoi.GnoiSonicService;
import io.lighty.modules.gnmi.simulatordevice.gnoi.GnoiSystemService;
import io.lighty.modules.gnmi.simulatordevice.utils.EffectiveModelContextBuilder;
import io.lighty.modules.gnmi.simulatordevice.utils.EffectiveModelContextBuilder.EffectiveModelContextBuilderException;
import io.lighty.modules.gnmi.simulatordevice.utils.FileUtils;
import io.lighty.modules.gnmi.simulatordevice.utils.UsernamePasswordAuth;
import io.lighty.modules.gnmi.simulatordevice.yang.YangDataService;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.internal.StringUtil;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import org.opendaylight.yangtools.binding.meta.YangModuleInfo;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class SimulatedGnmiDevice {

    private static final Logger LOG = LoggerFactory.getLogger(SimulatedGnmiDevice.class);

    private static final String DEFAULT_SERVER_CRT_FILE_PATH = "certs/server.crt";
    private static final String DEFAULT_SERVER_KEY_FILE_PATH = "certs/server-pkcs8.key";

    private final EventLoopGroup bossGroup;
    private final EventLoopGroup workerGroup;
    private final String host;
    private final String certificatePath;
    private final String keyPath;
    private final String yangsPath;
    private final Set modulesInfoSet;
    private final String initialConfigDataPath;
    private final String initialStateDataPath;
    private final UsernamePasswordAuth usernamePasswordAuth;
    private final int port;
    private final int maxConnections;
    private final boolean plaintext;
    private final Gson gson;
    private final EnumSet supportedEncodings;
    private Server server;
    private GnoiSystemService gnoiSystemService;
    private GnoiCertService gnoiCertService;
    private GnoiFileService gnoiFileService;
    private GnoiOSService gnoiOSService;
    private GnoiSonicService gnoiSonicService;
    private GnmiService gnmiService;
    private EffectiveModelContext schemaContext;
    private YangDataService dataService;


    public SimulatedGnmiDevice(final GnmiSimulatorConfiguration simulatorConfig) {
        this.bossGroup = Objects.requireNonNullElseGet(simulatorConfig.getBossGroup(),
                () -> new NioEventLoopGroup(1));
        this.workerGroup = Objects.requireNonNullElseGet(simulatorConfig.getWorkerGroup(), NioEventLoopGroup::new);
        this.yangsPath = simulatorConfig.getYangsPath();
        this.modulesInfoSet = simulatorConfig.getYangModulesInfo();
        this.host = simulatorConfig.getTargetAddress();
        this.port = simulatorConfig.getTargetPort();
        this.maxConnections = simulatorConfig.getMaxConnections();
        this.certificatePath = simulatorConfig.getCertPath();
        this.keyPath = simulatorConfig.getCertKeyPath();
        this.initialConfigDataPath = simulatorConfig.getInitialConfigDataPath();
        this.initialStateDataPath = simulatorConfig.getInitialStateDataPath();
        this.usernamePasswordAuth = new UsernamePasswordAuth(simulatorConfig.getUsername(),
                simulatorConfig.getPassword());
        this.plaintext = simulatorConfig.isUsePlaintext();
        this.gson = simulatorConfig.getGson();
        this.supportedEncodings = simulatorConfig.getSupportedEncodings();
    }

    public void start() throws IOException, EffectiveModelContextBuilderException {
        final NettyServerBuilder serverBuilder = NettyServerBuilder.forAddress(new InetSocketAddress(host, port))
                .bossEventLoopGroup(bossGroup)
                .workerEventLoopGroup(workerGroup)
                .channelType(NioServerSocketChannel.class)
                .withChildOption(ChannelOption.SO_KEEPALIVE, true)
                .withChildOption(ChannelOption.SO_BACKLOG, maxConnections);

        if (usernamePasswordAuth != null && usernamePasswordAuth.isNotEmpty()) {
            serverBuilder.intercept(new AuthenticationInterceptor(this.usernamePasswordAuth));
        }

        if (plaintext) {
            serverBuilder.protocolNegotiator(InternalProtocolNegotiators.plaintext());
        } else {
            if (StringUtil.isNullOrEmpty(certificatePath) || StringUtil.isNullOrEmpty(keyPath)) {
                // Use default certificates for insecure mode
                serverBuilder.useTransportSecurity(
                        FileUtils.getResourceAsStream(DEFAULT_SERVER_CRT_FILE_PATH),
                        FileUtils.getResourceAsStream(DEFAULT_SERVER_KEY_FILE_PATH)
                );
                LOG.info("Combination of server certificate and key not provided, using default ones.");
            } else {
                serverBuilder.useTransportSecurity(new File(certificatePath), new File(keyPath));
            }
        }

        // Initialize schema context from yang models
        schemaContext = new EffectiveModelContextBuilder()
                .addYangModulesPath(yangsPath)
                .addYangModulesInfo(modulesInfoSet)
                .build();

        // Initialize data service
        dataService = new YangDataService(schemaContext, initialConfigDataPath, initialStateDataPath);

        // Route gNMI calls towards gNMI service facade
        gnmiService = new GnmiService(schemaContext, dataService, gson, supportedEncodings);
        serverBuilder.addService(gnmiService);

        gnoiSystemService = new GnoiSystemService();
        serverBuilder.addService(gnoiSystemService);

        gnoiCertService = new GnoiCertService();
        serverBuilder.addService(gnoiCertService);

        gnoiFileService = new GnoiFileService();
        serverBuilder.addService(gnoiFileService);

        gnoiOSService = new GnoiOSService();
        serverBuilder.addService(gnoiOSService);

        gnoiSonicService = new GnoiSonicService();
        serverBuilder.addService(gnoiSonicService);

        // build & start
        LOG.info("Starting gNMI device simulator on {}:{} ...", host, port);
        this.server = serverBuilder.build();
        this.server.start();
        LOG.info("gNMI device simulator is up and running");
    }

    public void stop() {
        LOG.debug("Shutting down simulator...");
        if (!server.isShutdown()) {
            try {
                server.shutdown();
                server.awaitTermination();
            } catch (final InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new SimulatedGnmiDeviceException("Shutdown interrupted", e);
            }
        }
    }

    public String getHost() {
        return host;
    }

    public int getPort() {
        return port;
    }

    public GnoiSystemService getGnoiSystemService() {
        return gnoiSystemService;
    }

    public GnoiCertService getGnoiCertService() {
        return gnoiCertService;
    }

    public GnoiFileService getGnoiFileService() {
        return gnoiFileService;
    }

    public GnoiOSService getGnoiOSService() {
        return gnoiOSService;
    }

    public GnoiSonicService getGnoiSonicService() {
        return gnoiSonicService;
    }

    public GnmiService getGnmiService() {
        return gnmiService;
    }

    public YangDataService getDataService() {
        return dataService;
    }

    public EffectiveModelContext getSchemaContext() {
        return schemaContext;
    }

    static final class SimulatedGnmiDeviceException extends RuntimeException {
        SimulatedGnmiDeviceException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy