├── .github └── workflows │ ├── build.yml │ └── publish-simulator.yml ├── .gitignore ├── CONTRIBUTIONS ├── Dockerfile ├── LICENSE ├── README.md ├── examples ├── devices │ ├── lighty-actions-device │ │ ├── README.md │ │ ├── pom.xml │ │ └── src │ │ │ ├── assembly │ │ │ └── resources │ │ │ │ └── start-device.sh │ │ │ ├── main │ │ │ └── java │ │ │ │ └── io │ │ │ │ └── lighty │ │ │ │ └── netconf │ │ │ │ └── device │ │ │ │ └── action │ │ │ │ ├── Main.java │ │ │ │ ├── actions │ │ │ │ ├── ResetAction.java │ │ │ │ └── StartAction.java │ │ │ │ └── processors │ │ │ │ ├── ActionServiceDeviceProcessor.java │ │ │ │ ├── ResetActionProcessor.java │ │ │ │ └── StartActionProcessor.java │ │ │ └── test │ │ │ ├── java │ │ │ └── io │ │ │ │ └── lighty │ │ │ │ └── netconf │ │ │ │ └── device │ │ │ │ └── action │ │ │ │ └── ActionDeviceTest.java │ │ │ └── resources │ │ │ ├── get_schemas_request.xml │ │ │ ├── reset_action_request.xml │ │ │ └── start_action_request.xml │ ├── lighty-network-topology-device │ │ ├── README.md │ │ ├── pom.xml │ │ └── src │ │ │ ├── assembly │ │ │ └── resources │ │ │ │ ├── netconf-topology-device-requests.postman_collection.json │ │ │ │ └── start-device.sh │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── io │ │ │ │ │ └── lighty │ │ │ │ │ └── netconf │ │ │ │ │ └── device │ │ │ │ │ └── topology │ │ │ │ │ ├── Main.java │ │ │ │ │ ├── datastore │ │ │ │ │ ├── DataTreeChangeListenerActivator.java │ │ │ │ │ └── TopologyDataTreeChangeListener.java │ │ │ │ │ ├── processors │ │ │ │ │ ├── EmptyInput.java │ │ │ │ │ ├── NetworkTopologyServiceAbstractProcessor.java │ │ │ │ │ ├── NetworkTopologyServiceAddNodeToTopologyProcessor.java │ │ │ │ │ ├── NetworkTopologyServiceCreateTopologyProcessor.java │ │ │ │ │ ├── NetworkTopologyServiceGetNodeFromTopologyProcessor.java │ │ │ │ │ ├── NetworkTopologyServiceGetTopologiesProcessor.java │ │ │ │ │ ├── NetworkTopologyServiceGetTopologyByIdProcessor.java │ │ │ │ │ ├── NetworkTopologyServiceGetTopologyIdsProcessor.java │ │ │ │ │ ├── NetworkTopologyServiceRemoveAllTopologiesProcessor.java │ │ │ │ │ ├── NetworkTopologyServiceRemoveNodeProcessor.java │ │ │ │ │ └── NetworkTopologyServiceRemoveTopologyProcessor.java │ │ │ │ │ └── rpcs │ │ │ │ │ └── NetworkTopologyServiceImpl.java │ │ │ └── resources │ │ │ │ ├── initial-network-topo-config-datastore.xml │ │ │ │ └── initial-network-topo-operational-datastore.xml │ │ │ └── test │ │ │ ├── java │ │ │ └── io │ │ │ │ └── lighty │ │ │ │ └── netconf │ │ │ │ └── device │ │ │ │ └── topology │ │ │ │ ├── DeviceTest.java │ │ │ │ └── TestUtils.java │ │ │ └── resources │ │ │ ├── add_node_rpc_request.xml │ │ │ ├── add_node_rpc_response.xml │ │ │ ├── create_topology_config_request.xml │ │ │ ├── create_topology_rpc_request.xml │ │ │ ├── create_topology_rpc_response.xml │ │ │ ├── delete_topology_config_request.xml │ │ │ ├── delete_topology_rpc_request.xml │ │ │ ├── delete_topology_rpc_response.xml │ │ │ ├── get_config_request.xml │ │ │ ├── get_schemas_request.xml │ │ │ └── merge_topology_config_request.xml │ ├── lighty-notifications-device │ │ ├── README.md │ │ ├── pom.xml │ │ └── src │ │ │ ├── assembly │ │ │ └── resources │ │ │ │ └── start-device.sh │ │ │ ├── main │ │ │ └── java │ │ │ │ └── io │ │ │ │ └── lighty │ │ │ │ └── netconf │ │ │ │ └── device │ │ │ │ └── notification │ │ │ │ ├── Main.java │ │ │ │ └── processors │ │ │ │ └── TriggerNotificationProcessor.java │ │ │ └── test │ │ │ ├── java │ │ │ └── io │ │ │ │ └── lighty │ │ │ │ └── devices │ │ │ │ └── notification │ │ │ │ └── tests │ │ │ │ ├── NotificationNetconfSessionListener.java │ │ │ │ └── NotificationTest.java │ │ │ └── resources │ │ │ ├── get_schemas_request.xml │ │ │ ├── subcribe_to_notifications_request.xml │ │ │ └── trigger_data_notification_request.xml │ ├── lighty-toaster-device │ │ ├── README.md │ │ ├── pom.xml │ │ └── src │ │ │ ├── assembly │ │ │ └── resources │ │ │ │ └── start-device.sh │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── io │ │ │ │ │ └── lighty │ │ │ │ │ └── netconf │ │ │ │ │ └── device │ │ │ │ │ └── toaster │ │ │ │ │ ├── Main.java │ │ │ │ │ ├── processors │ │ │ │ │ ├── ToasterServiceAbstractProcessor.java │ │ │ │ │ ├── ToasterServiceCancelToastProcessor.java │ │ │ │ │ ├── ToasterServiceMakeToastProcessor.java │ │ │ │ │ └── ToasterServiceRestockToasterProcessor.java │ │ │ │ │ └── rpcs │ │ │ │ │ └── ToasterServiceImpl.java │ │ │ └── resources │ │ │ │ ├── initial-toaster-config-datastore.xml │ │ │ │ └── initial-toaster-operational-datastore.xml │ │ │ └── test │ │ │ ├── java │ │ │ └── io │ │ │ │ └── lighty │ │ │ │ └── netconf │ │ │ │ └── device │ │ │ │ └── toaster │ │ │ │ ├── NotificationNetconfSessionListener.java │ │ │ │ └── ToasterDeviceTest.java │ │ │ └── resources │ │ │ ├── create_toaster_request.xml │ │ │ ├── get_schemas_request.xml │ │ │ ├── get_toaster_data_request.xml │ │ │ ├── make_toast_request.xml │ │ │ ├── restock_toast_request.xml │ │ │ └── subscribe_to_notifications_request.xml │ ├── lighty-toaster-multiple-devices │ │ ├── README.md │ │ ├── pom.xml │ │ └── src │ │ │ ├── assembly │ │ │ └── resources │ │ │ │ └── start-device.sh │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── io │ │ │ │ │ └── lighty │ │ │ │ │ └── netconf │ │ │ │ │ └── device │ │ │ │ │ └── toaster │ │ │ │ │ └── Main.java │ │ │ └── resources │ │ │ │ ├── initial-toaster-config-datastore.xml │ │ │ │ └── initial-toaster-operational-datastore.xml │ │ │ └── test │ │ │ ├── java │ │ │ └── io │ │ │ │ └── lighty │ │ │ │ └── netconf │ │ │ │ └── device │ │ │ │ └── toaster │ │ │ │ └── DeviceTest.java │ │ │ └── resources │ │ │ ├── create_toaster_request.xml │ │ │ ├── get_schemas_request.xml │ │ │ ├── get_toaster_data_request.xml │ │ │ └── make_toast_request.xml │ └── pom.xml ├── models │ ├── lighty-example-data-center-model │ │ ├── README.md │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── yang │ │ │ └── example-data-center@2018-08-07.yang │ ├── lighty-example-network-topology-device-model │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── yang │ │ │ └── network-topology-rpcs@2023-09-27.yang │ ├── lighty-example-notifications-model │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── yang │ │ │ └── lighty-test-notifications@2018-08-20.yang │ └── pom.xml ├── parents │ ├── examples-bom │ │ ├── README.md │ │ └── pom.xml │ ├── examples-parent │ │ ├── README.md │ │ └── pom.xml │ └── pom.xml └── pom.xml ├── lgtm.yml ├── lighty-netconf-device ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── lighty │ │ └── netconf │ │ └── device │ │ ├── NetconfDevice.java │ │ ├── NetconfDeviceBuilder.java │ │ ├── NetconfDeviceImpl.java │ │ ├── NetconfDeviceServices.java │ │ ├── NetconfDeviceServicesImpl.java │ │ ├── requests │ │ ├── BaseRequestProcessor.java │ │ ├── CommitRequestProcessor.java │ │ ├── DatastoreOutputRequestProcessor.java │ │ ├── DeleteConfigRequestProcessor.java │ │ ├── EditConfigRequestProcessor.java │ │ ├── GetConfigRequestProcessor.java │ │ ├── GetRequestProcessor.java │ │ ├── OkOutputRequestProcessor.java │ │ ├── RequestProcessor.java │ │ ├── RpcHandlerImpl.java │ │ ├── RpcOutputRequestProcessor.java │ │ └── notification │ │ │ ├── CreateSubscriptionRequestProcessor.java │ │ │ ├── NotificationOperation.java │ │ │ ├── NotificationPublishService.java │ │ │ ├── NotificationPublishServiceImpl.java │ │ │ └── NotificationService.java │ │ ├── response │ │ ├── Response.java │ │ ├── ResponseData.java │ │ └── ResponseErrorMessage.java │ │ └── utils │ │ ├── ArgumentParser.java │ │ ├── DefaultOperation.java │ │ ├── ModelUtils.java │ │ ├── Operation.java │ │ ├── RPCUtil.java │ │ └── TimeoutUtil.java │ └── test │ ├── java │ └── io │ │ └── lighty │ │ └── netconf │ │ └── device │ │ └── NetconfDeviceImplTest.java │ └── resources │ └── initial-network-topo-config-datastore.xml └── pom.xml /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Build 5 | 6 | on: 7 | push: 8 | branches: 9 | - '**' 10 | pull_request: 11 | types: [opened, synchronize, reopened] 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 18 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 19 | SONAR_ORGANIZATION: ${{ secrets.SONAR_ORGANIZATION }} 20 | SONAR_PROJECT_KEY: ${{ secrets.SONAR_PROJECT_KEY}} 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Set up JDK 21 24 | uses: actions/setup-java@v3 25 | with: 26 | java-version: 21 27 | distribution: 'temurin' 28 | - name: Set up Maven 29 | uses: stCarolas/setup-maven@v5 30 | with: 31 | maven-version: 3.9.8 32 | - name: Cache SonarCloud packages 33 | uses: actions/cache@v4 34 | if: ${{ env.SONAR_TOKEN != 0 }} 35 | with: 36 | path: ~/.sonar/cache 37 | key: ${{ runner.os }}-sonar 38 | restore-keys: ${{ runner.os }}-sonar 39 | - name: Cache Maven packages 40 | uses: actions/cache@v4 41 | with: 42 | path: ~/.m2 43 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} 44 | restore-keys: ${{ runner.os }}-m2 45 | - name: Maven install + Test 46 | if: ${{ env.SONAR_TOKEN == 0 }} 47 | run: mvn clean install -B -V -Psource-quality 48 | - name: Maven install + Test + SonarCloud 49 | if: ${{ env.SONAR_TOKEN != 0 }} 50 | run: mvn clean install org.sonarsource.scanner.maven:sonar-maven-plugin:sonar 51 | -Dsonar.java.source=21 52 | -Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }} 53 | -Dsonar.organization=${{ env.SONAR_ORGANIZATION }} 54 | -Dsonar.host.url=https://sonarcloud.io 55 | -B -V -Psource-quality 56 | - name: Upload surefire test results 57 | uses: actions/upload-artifact@v4 58 | with: 59 | name: Surefire-Test-Results 60 | path: ~/**/surefire-reports/**/*.txt -------------------------------------------------------------------------------- /.github/workflows/publish-simulator.yml: -------------------------------------------------------------------------------- 1 | name: Publish netconf-simulator 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | version: 6 | description: Desired version of published docker image & helm charts, e.g. "XX.YY.ZZ" 7 | required: true 8 | image-tag-latest: 9 | description: Should be this docker labeled with tag latest? Enter `true` if the tag `latest` should be added for image. 10 | default: "true" 11 | required: true 12 | publish-access-key: 13 | description: The branch, tag or SHA to checkout. (if "default" the selected branch will be used) 14 | default: default 15 | required: true 16 | 17 | jobs: 18 | publish-docker-helm: 19 | runs-on: ubuntu-latest 20 | defaults: 21 | run: 22 | shell: bash 23 | env: 24 | IMAGE_NAME: "lighty-network-topology-device" 25 | PUBLISH_ACCESS_KEY: ${{ secrets.MM_PKG_WRITE }} 26 | name: "Publish netconf-simulator docker image. Checkout-ref: ${{ github.event.inputs.publish-access-key }}" 27 | steps: 28 | - name: Checkout code 29 | uses: actions/checkout@v3 30 | 31 | - name: Set up JDK 21 32 | uses: actions/setup-java@v3 33 | with: 34 | java-version: 21 35 | distribution: 'temurin' 36 | 37 | - name: Build lighty-netconf-simulator 38 | shell: bash 39 | run: | 40 | echo "Building lighty-netconf-simulator..." 41 | mvn install -DskipTests 42 | 43 | - name: Run docker:build... 44 | shell: bash 45 | run: | 46 | 47 | echo "Image name set to:" ${{ env.IMAGE_NAME }} 48 | 49 | DOCKER_IMAGE_NAME=${{env.IMAGE_NAME}} 50 | DOCKER_IMAGE_NAME_TAG=$(echo $DOCKER_IMAGE_NAME:${{ inputs.version }}) 51 | DOCKER_IMAGE_NAME_GHCR=$(echo ghcr.io/pantheontech/${{ env.IMAGE_NAME }}) 52 | DOCKER_IMAGE_NAME_GHCR_TAG=$(echo $DOCKER_IMAGE_NAME_GHCR:${{ inputs.version }}) 53 | 54 | echo "docker build -t $DOCKER_IMAGE_NAME ." 55 | docker build -t $DOCKER_IMAGE_NAME . 56 | 57 | echo "Docker image tag:" $DOCKER_IMAGE_NAME_GHCR $DOCKER_IMAGE_NAME_GHCR_TAG 58 | docker tag $DOCKER_IMAGE_NAME $DOCKER_IMAGE_NAME_TAG 59 | if [ "${{ inputs.image-tag-latest }}" = 'true' ]; then 60 | docker tag $DOCKER_IMAGE_NAME $DOCKER_IMAGE_NAME:latest 61 | fi 62 | docker images | grep $DOCKER_IMAGE_NAME 63 | - name: List docker images 64 | shell: bash 65 | run: | 66 | docker images 67 | - name: Docker log in (ghcr.io) 68 | shell: bash 69 | run: | 70 | echo ${{ inputs.publish-access-key}} | docker login --username ${{ github.actor }} --password-stdin ghcr.io 71 | - name: Publish docker image (ghcr.io) 72 | shell: bash 73 | run: | 74 | docker push $DOCKER_IMAGE_NAME_GHCR_TAG 75 | if [ "${{ inputs.image-tag-latest }}" = 'true' ]; then 76 | docker push $DOCKER_IMAGE_NAME_GHCR:latest 77 | fi 78 | - name: Check if docker image is pullable (ghcr.io) 79 | shell: bash 80 | run: | 81 | docker rmi $DOCKER_IMAGE_NAME_GHCR_TAG 82 | docker pull $DOCKER_IMAGE_NAME_GHCR_TAG 83 | - name: Install yq (yaml processor) 84 | shell: bash 85 | run: | 86 | sudo snap install yq 87 | - name: Set image.name, image.version in values.yaml of helm chart 88 | shell: bash 89 | run: | 90 | yq eval '.image.name="ghcr.io/pantheontech/$'"IMAGE_NAME"'" | .image.version="'${{ inputs.version }}'"' "${{ inputs.app-helm-values-path }}" -i 91 | - name: Print values.yaml 92 | shell: bash 93 | run: | 94 | cat -A ${{ inputs.app-helm-values-path }} 95 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | **/target 3 | **/test-output 4 | **/journal 5 | **/snapshots 6 | 7 | bin/ 8 | dist 9 | .idea 10 | .classpath 11 | .project 12 | .settings 13 | 14 | *.iml 15 | *.ipr 16 | *.iws 17 | 18 | persistence 19 | -------------------------------------------------------------------------------- /CONTRIBUTIONS: -------------------------------------------------------------------------------- 1 | Contributions to lighty-netconf-simulator 2 | ---------------------------- 3 | 4 | This software is distributed under Eclipse Public License 1.0 5 | and any contribution to the program must be compliant with this 6 | license. 7 | 8 | To indicate your acceptance of Developer's Certificate of Origin 1.1 9 | terms and licensing of the contribution under the EPL v 1.0 license 10 | terms, please add the following line to the end of the commit message 11 | ("git commit -s") for each contribution you make to the project: 12 | 13 | Signed-off-by: Your Name 14 | 15 | 16 | ---------------------------------- 17 | [http://developercertificate.org/] 18 | ---------------------------------- 19 | 20 | Developer Certificate of Origin 21 | Version 1.1 22 | 23 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 24 | 1 Letterman Drive 25 | Suite D4700 26 | San Francisco, CA, 94129 27 | 28 | Everyone is permitted to copy and distribute verbatim copies of this 29 | license document, but changing it is not allowed. 30 | 31 | 32 | Developer's Certificate of Origin 1.1 33 | 34 | By making a contribution to this project, I certify that: 35 | 36 | (a) The contribution was created in whole or in part by me and I 37 | have the right to submit it under the open source license 38 | indicated in the file; or 39 | 40 | (b) The contribution is based upon previous work that, to the best 41 | of my knowledge, is covered under an appropriate open source 42 | license and I have the right under that license to submit that 43 | work with modifications, whether created in whole or in part 44 | by me, under the same open source license (unless I am 45 | permitted to submit under a different license), as indicated 46 | in the file; or 47 | 48 | (c) The contribution was provided directly to me by some other 49 | person who certified (a), (b) or (c) and I have not modified 50 | it. 51 | 52 | (d) I understand and agree that this project and the contribution 53 | are public and that a record of the contribution (including all 54 | personal information I submit with it, including my sign-off) is 55 | maintained indefinitely and may be redistributed consistent with 56 | this project or the open source license(s) involved. 57 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VERSION="22.0.0-SNAPSHOT" 2 | 3 | FROM maven:3.9-eclipse-temurin-21-alpine as build 4 | 5 | ARG VERSION 6 | 7 | WORKDIR /lighty-netconf-simulator 8 | 9 | COPY . ./ 10 | 11 | RUN mvn install -DskipTests 12 | 13 | WORKDIR /lighty-netconf-simulator/examples/devices/lighty-network-topology-device 14 | 15 | RUN unzip target/lighty-network-topology-device-$VERSION-bin.zip -d target/ 16 | 17 | RUN mv target/lighty-network-topology-device-$VERSION target/lighty-network-topology-device 18 | RUN mv target/lighty-network-topology-device/lighty-network-topology-device-$VERSION.jar target/lighty-network-topology-device/lighty-network-topology-device.jar 19 | 20 | FROM eclipse-temurin:21-jre-alpine 21 | 22 | ARG VERSION 23 | 24 | COPY --from=build /lighty-netconf-simulator/examples/devices/lighty-network-topology-device/target/lighty-network-topology-device /app/target 25 | COPY --from=build /lighty-netconf-simulator/examples/devices/lighty-network-topology-device/src/main/resources /app/target/resources 26 | 27 | WORKDIR /app/target 28 | 29 | EXPOSE 17380 30 | 31 | ENTRYPOINT ["java", "-jar", "lighty-network-topology-device.jar"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lighty.io NETCONF Device Simulator (& Libraries) 2 | 3 | A lightweight project that provides: 4 | - **NETCONF Device Libraries** for building custom NETCONF devices 5 | - **Examples of NETCONF Device Simulators** to demonstrate, how these libraries can be used to create custom NETCONF devices 6 | 7 | ## NETCONF Device Libraries 8 | `lighty-netconf-device` is a NETCONF device library for creating 9 | custom NETCONF devices. With the provided NETCONF device builder, 10 | you can create your own device. This device can be built with the use of builder switches for 11 | adding custom YANG models, custom request processors & more. 12 | 13 | ## Build & Run 14 | * Build the project with Java 21: 15 | ``` 16 | mvn clean install 17 | ``` 18 | * The NETCONF Device Library build is located at: 19 | 20 | `lighty-netconf-device\target\lighty-netconf-device-22.0.0-SNAPSHOT.jar` 21 | 22 | * The build & run procedures for the example devices are described in each device's README. 23 | 24 | ## Example NETCONF Device Simulators 25 | This tool contains 5 device examples, to demonstrate the usage of the NETCONF Device Library for creating custom devices: 26 | - [**lighty Actions Device**](./examples/devices/lighty-actions-device/README.md) 27 | - [**lighty Network Topology Device**](./examples/devices/lighty-network-topology-device/README.md) 28 | - [**lighty Notifications Device**](./examples/devices/lighty-notifications-device/README.md) 29 | - [**lighty Toaster Device**](./examples/devices/lighty-toaster-device/README.md) 30 | - [**lighty Toaster Multiple Devices**](./examples/devices/lighty-toaster-multiple-devices/README.md) 31 | 32 | [Read about the background of this project here.](https://pantheon.tech/netconf-monitoring-get-schema/) 33 | 34 | ## Running the application using docker 35 | 1. Build the application dockerfile using `docker build -t lighty-netconf-simulator .` 36 | 2. Run the dockerfile using `docker run --name lighty-netconf-simulator -p 17830:17830 lighty-netconf-simulator -i resources/ -o resources/` 37 | 3. Get ip address using `docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' lighty-netconf-simulator` 38 | 4. Start lighty.io or other controller and connect to the device 39 | 5. Make changes to the device. example: 40 | ``` 41 | curl --location 'http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=new-netconf-device/yang-ext:mount/network-topology:network-topology/topology=default-topology' \ 42 | --header 'Content-Type: application/json' \ 43 | --data '{ 44 | "node": [ 45 | { 46 | "node-id": "test-12345" 47 | } 48 | ] 49 | }' 50 | ``` 51 | 6. Stop the docker container 52 | 7. Restart the docker container using `docker start lighty-netconf-simulator` 53 | 54 | ## Known Issues 55 | 56 | **Problem:** Creating multiple simulators takes a long time. 57 | Delay can be caused by Random Number Generation `/dev/random`. 58 | **Solution:** Use /dev/urandom instead of /dev/random by passing it as system property 59 | `-Djava.security.egd=file:/dev/./urandom` or modify file `$JAVA_HOME/jre/lib/security/java.security` 60 | by changing property `securerandom.source=file:/dev/random` 61 | to `securerandom.source=file:/dev/urandom`. -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | 15 | io.lighty.netconf.device.examples 16 | examples-parent 17 | 22.0.0-SNAPSHOT 18 | ../../parents/examples-parent/pom.xml 19 | 20 | 21 | lighty-actions-device 22 | jar 23 | 24 | 25 | io.lighty.netconf.device.action.Main 26 | true 27 | 28 | 29 | 30 | 31 | io.lighty.netconf.device.examples.models 32 | lighty-example-data-center-model 33 | 34 | 35 | io.lighty.netconf.device 36 | lighty-netconf-device 37 | 38 | 39 | com.github.spotbugs 40 | spotbugs-annotations 41 | 42 | 43 | 44 | org.junit.jupiter 45 | junit-jupiter-api 46 | test 47 | 48 | 49 | org.junit.jupiter 50 | junit-jupiter-engine 51 | test 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/src/assembly/resources/start-device.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The script accepts one parameter signifying the listening port of the NETCONF server. 4 | # 5 | # ./start-device 6 | # 7 | # When run without a parameter a default port 17830 will be used. 8 | 9 | CLASSPATH=lighty-action-device-22.0.0-SNAPSHOT.jar 10 | 11 | for jar in `ls -1 lib/`; 12 | do 13 | CLASSPATH=$CLASSPATH:lib/$jar 14 | done 15 | 16 | #echo $CLASSPATH 17 | java -server -Xms16M -Xmx40M -XX:MaxMetaspaceSize=40m -classpath $CLASSPATH io.lighty.netconf.device.action.Main $1 18 | -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/src/main/java/io/lighty/netconf/device/action/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.action; 9 | 10 | import com.google.common.collect.ImmutableSet; 11 | import io.lighty.netconf.device.NetconfDevice; 12 | import io.lighty.netconf.device.NetconfDeviceBuilder; 13 | import io.lighty.netconf.device.action.processors.ActionServiceDeviceProcessor; 14 | import java.util.Set; 15 | import org.opendaylight.yangtools.binding.meta.YangModuleInfo; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | public class Main { 20 | 21 | private static final Logger LOG = LoggerFactory.getLogger(Main.class); 22 | public static final Set ACTION_MODEL_PATHS = ImmutableSet.of( 23 | org.opendaylight.yang.svc.v1.urn.example.data.center.rev180807.YangModuleInfoImpl.getInstance()); 24 | 25 | private ShutdownHook shutdownHook; 26 | 27 | public static void main(String[] args) { 28 | Main app = new Main(); 29 | app.start(args, true); 30 | } 31 | 32 | public void start(String[] args) { 33 | start(args, false); 34 | } 35 | 36 | public void start(String[] args, boolean registerShutdownHook) { 37 | final int port = getPortFromArgs(args); 38 | 39 | final NetconfDevice netconfDevice = new NetconfDeviceBuilder() 40 | .setCredentials("admin", "admin") 41 | .setBindingPort(port) 42 | .withModels(ACTION_MODEL_PATHS) 43 | .withDefaultRequestProcessors() 44 | .withDefaultCapabilities() 45 | .withRequestProcessor(new ActionServiceDeviceProcessor()) 46 | .build(); 47 | netconfDevice.start(); 48 | 49 | //5. Register shutdown hook 50 | this.shutdownHook = new ShutdownHook(netconfDevice); 51 | if (registerShutdownHook) { 52 | Runtime.getRuntime().addShutdownHook(this.shutdownHook); 53 | } 54 | } 55 | 56 | public void shutdown() { 57 | if (this.shutdownHook != null) { 58 | this.shutdownHook.execute(); 59 | } 60 | } 61 | 62 | private static class ShutdownHook extends Thread { 63 | private final NetconfDevice netConfDevice; 64 | 65 | ShutdownHook(final NetconfDevice netConfDevice) { 66 | this.netConfDevice = netConfDevice; 67 | } 68 | 69 | @Override 70 | public void run() { 71 | this.execute(); 72 | } 73 | 74 | @SuppressWarnings("checkstyle:IllegalCatch") 75 | public void execute() { 76 | LOG.info("Shutting down Lighty-Action device."); 77 | if (this.netConfDevice != null) { 78 | try { 79 | this.netConfDevice.close(); 80 | } catch (final Exception e) { 81 | LOG.error("Failed to close Netconf device properly", e); 82 | } 83 | } 84 | } 85 | } 86 | 87 | @SuppressWarnings("checkstyle:IllegalCatch") 88 | private static int getPortFromArgs(final String[] args) { 89 | try { 90 | return Integer.parseInt(args[0]); 91 | } catch (final Exception e) { 92 | return 17830; 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/src/main/java/io/lighty/netconf/device/action/actions/ResetAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.action.actions; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.Server; 12 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.ServerKey; 13 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.server.Reset; 14 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.server.ResetInput; 15 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.server.ResetOutput; 16 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.server.ResetOutputBuilder; 17 | import org.opendaylight.yangtools.binding.DataObjectIdentifier; 18 | import org.opendaylight.yangtools.util.concurrent.FluentFutures; 19 | import org.opendaylight.yangtools.yang.common.RpcResult; 20 | import org.opendaylight.yangtools.yang.common.RpcResultBuilder; 21 | 22 | public class ResetAction implements Reset { 23 | 24 | @Override 25 | public ListenableFuture> invoke(final DataObjectIdentifier.WithKey path, 26 | final ResetInput input) { 27 | final String resetAt = input.getResetAt(); 28 | return FluentFutures.immediateFluentFuture(RpcResultBuilder.success(new ResetOutputBuilder().setResetFinishedAt( 29 | resetAt).build()).build()); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/src/main/java/io/lighty/netconf/device/action/actions/StartAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.action.actions; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.Device; 12 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.device.Start; 13 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.device.StartInput; 14 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.device.StartOutput; 15 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.device.StartOutputBuilder; 16 | import org.opendaylight.yangtools.binding.DataObjectIdentifier; 17 | import org.opendaylight.yangtools.util.concurrent.FluentFutures; 18 | import org.opendaylight.yangtools.yang.common.RpcResult; 19 | import org.opendaylight.yangtools.yang.common.RpcResultBuilder; 20 | 21 | public class StartAction implements Start { 22 | 23 | @Override 24 | public ListenableFuture> invoke(DataObjectIdentifier path, StartInput input) { 25 | final String startAt = input.getStartAt(); 26 | return FluentFutures.immediateFluentFuture(RpcResultBuilder.success(new StartOutputBuilder().setStartFinishedAt( 27 | startAt).build()).build()); 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/src/main/java/io/lighty/netconf/device/action/processors/ResetActionProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.action.processors; 9 | 10 | import com.google.common.base.Preconditions; 11 | import com.google.common.util.concurrent.FutureCallback; 12 | import com.google.common.util.concurrent.Futures; 13 | import com.google.common.util.concurrent.ListenableFuture; 14 | import io.lighty.codecs.util.XmlNodeConverter; 15 | import io.lighty.codecs.util.exception.DeserializationException; 16 | import io.lighty.netconf.device.response.Response; 17 | import io.lighty.netconf.device.response.ResponseData; 18 | import io.lighty.netconf.device.utils.RPCUtil; 19 | import java.io.Reader; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.concurrent.CompletableFuture; 23 | import java.util.concurrent.Executors; 24 | import javax.xml.transform.TransformerException; 25 | import org.opendaylight.mdsal.binding.dom.adapter.ConstantAdapterContext; 26 | import org.opendaylight.mdsal.binding.dom.adapter.CurrentAdapterSerializer; 27 | import org.opendaylight.netconf.api.DocumentedException; 28 | import org.opendaylight.netconf.api.xml.XmlElement; 29 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.Server; 30 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.ServerKey; 31 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.server.Reset; 32 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.server.ResetInput; 33 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.server.ResetOutput; 34 | import org.opendaylight.yangtools.binding.data.codec.spi.BindingDOMCodecServices; 35 | import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 36 | import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; 37 | import org.opendaylight.yangtools.yang.common.RpcResult; 38 | import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; 39 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 40 | import org.opendaylight.yangtools.yang.model.api.ActionDefinition; 41 | import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; 42 | import org.slf4j.Logger; 43 | import org.slf4j.LoggerFactory; 44 | import org.w3c.dom.Element; 45 | import org.w3c.dom.Node; 46 | import org.w3c.dom.NodeList; 47 | 48 | public final class ResetActionProcessor extends ActionServiceDeviceProcessor { 49 | 50 | private static final Logger LOG = LoggerFactory.getLogger(ResetActionProcessor.class); 51 | 52 | private final Reset resetAction; 53 | private final Absolute path; 54 | private final ActionDefinition definition; 55 | private final CurrentAdapterSerializer adapterSerializer; 56 | 57 | public ResetActionProcessor(final Reset resetAction, final Absolute path, final ActionDefinition definition, 58 | final BindingDOMCodecServices codecServices) { 59 | this.resetAction = resetAction; 60 | this.path = path; 61 | this.definition = definition; 62 | this.adapterSerializer = new ConstantAdapterContext(codecServices).currentSerializer(); 63 | } 64 | 65 | @SuppressWarnings({"rawtypes", "unchecked", "checkstyle:IllegalCatch"}) 66 | @Override 67 | protected CompletableFuture execute(final Element requestXmlElement) { 68 | final XmlNodeConverter xmlNodeConverter = getNetconfDeviceServices().getXmlNodeConverter(); 69 | try { 70 | final XmlElement xmlElement = XmlElement.fromDomElement(requestXmlElement); 71 | final Element actionElement = findInputElement(xmlElement, this.definition.getQName()); 72 | final Reader readerFromElement = RPCUtil.createReaderFromElement(actionElement); 73 | final Absolute actionInput = getActionInput(this.path, this.definition); 74 | final ContainerNode deserializedNode = (ContainerNode) xmlNodeConverter 75 | .deserialize(actionInput, readerFromElement); 76 | final ResetInput input = this.adapterSerializer.fromNormalizedNodeActionInput(Reset.class, 77 | deserializedNode); 78 | final String key = findNameElement(xmlElement); 79 | Preconditions.checkNotNull(key); 80 | final Class listItem = Server.class; 81 | final ServerKey listKey = new ServerKey(key); 82 | final InstanceIdentifier instanceIdentifier = InstanceIdentifier.builder(listItem, listKey).build(); 83 | final KeyedInstanceIdentifier keydIID 84 | = (KeyedInstanceIdentifier) instanceIdentifier; 85 | 86 | final ListenableFuture> outputFuture = 87 | this.resetAction.invoke(keydIID.toIdentifier(), input); 88 | final CompletableFuture completableFuture = new CompletableFuture<>(); 89 | Futures.addCallback(outputFuture, new FutureCallback>() { 90 | 91 | @Override 92 | public void onSuccess(final RpcResult result) { 93 | final NormalizedNode domOutput = ResetActionProcessor.this.adapterSerializer 94 | .toNormalizedNodeActionOutput(Reset.class, result.getResult()); 95 | final List list = new ArrayList<>(); 96 | list.add(domOutput); 97 | completableFuture.complete(new ResponseData(list)); 98 | } 99 | 100 | @Override 101 | public void onFailure(final Throwable throwable) { 102 | } 103 | }, Executors.newSingleThreadExecutor()); 104 | return completableFuture; 105 | } catch (final TransformerException | DocumentedException | DeserializationException e) { 106 | throw new RuntimeException(e); 107 | } 108 | } 109 | 110 | private String findNameElement(final XmlElement xmlElement) throws DocumentedException { 111 | final NodeList elementsByTagName = xmlElement.getDomElement().getOwnerDocument().getElementsByTagName("name"); 112 | final Node item = elementsByTagName.item(0); 113 | return item.getFirstChild().getNodeValue(); 114 | } 115 | 116 | @Override 117 | protected ActionDefinition getActionDefinition() { 118 | return this.definition; 119 | } 120 | 121 | @Override 122 | protected Absolute getActionPath() { 123 | return this.path; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/src/main/java/io/lighty/netconf/device/action/processors/StartActionProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.action.processors; 9 | 10 | import com.google.common.util.concurrent.FutureCallback; 11 | import com.google.common.util.concurrent.Futures; 12 | import com.google.common.util.concurrent.ListenableFuture; 13 | import io.lighty.codecs.util.XmlNodeConverter; 14 | import io.lighty.codecs.util.exception.DeserializationException; 15 | import io.lighty.netconf.device.response.Response; 16 | import io.lighty.netconf.device.response.ResponseData; 17 | import io.lighty.netconf.device.utils.RPCUtil; 18 | import java.io.Reader; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.concurrent.CompletableFuture; 22 | import java.util.concurrent.Executors; 23 | import javax.xml.transform.TransformerException; 24 | import org.opendaylight.mdsal.binding.dom.adapter.ConstantAdapterContext; 25 | import org.opendaylight.mdsal.binding.dom.adapter.CurrentAdapterSerializer; 26 | import org.opendaylight.netconf.api.DocumentedException; 27 | import org.opendaylight.netconf.api.xml.XmlElement; 28 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.Device; 29 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.device.Start; 30 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.device.StartInput; 31 | import org.opendaylight.yang.gen.v1.urn.example.data.center.rev180807.device.StartOutput; 32 | import org.opendaylight.yangtools.binding.DataObjectIdentifier; 33 | import org.opendaylight.yangtools.binding.data.codec.spi.BindingDOMCodecServices; 34 | import org.opendaylight.yangtools.yang.common.RpcResult; 35 | import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; 36 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 37 | import org.opendaylight.yangtools.yang.model.api.ActionDefinition; 38 | import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; 39 | import org.slf4j.Logger; 40 | import org.slf4j.LoggerFactory; 41 | import org.w3c.dom.Element; 42 | 43 | public final class StartActionProcessor extends ActionServiceDeviceProcessor { 44 | 45 | private static final Logger LOG = LoggerFactory.getLogger(StartActionProcessor.class); 46 | 47 | private final Start startAction; 48 | private final Absolute path; 49 | private final ActionDefinition definition; 50 | private final CurrentAdapterSerializer adapterSerializer; 51 | 52 | public StartActionProcessor(final Start startAction, final Absolute path, final ActionDefinition definition, 53 | final BindingDOMCodecServices codecServices) { 54 | this.startAction = startAction; 55 | this.path = path; 56 | this.definition = definition; 57 | this.adapterSerializer = new ConstantAdapterContext(codecServices).currentSerializer(); 58 | } 59 | 60 | @SuppressWarnings("checkstyle:IllegalCatch") 61 | @Override 62 | protected CompletableFuture execute(final Element requestXmlElement) { 63 | final XmlNodeConverter xmlNodeConverter = getNetconfDeviceServices().getXmlNodeConverter(); 64 | try { 65 | final XmlElement xmlElement = XmlElement.fromDomElement(requestXmlElement); 66 | final Element actionElement = findInputElement(xmlElement, this.definition.getQName()); 67 | final Reader readerFromElement = RPCUtil.createReaderFromElement(actionElement); 68 | final Absolute actionInput = getActionInput(this.path, this.definition); 69 | final ContainerNode deserializedNode = (ContainerNode) xmlNodeConverter.deserialize(actionInput, 70 | readerFromElement); 71 | final StartInput input = this.adapterSerializer.fromNormalizedNodeActionInput(Start.class, 72 | deserializedNode); 73 | final ListenableFuture> outputFuture = this.startAction 74 | .invoke(DataObjectIdentifier.builder(Device.class).build(), input); 75 | final CompletableFuture completableFuture = new CompletableFuture<>(); 76 | Futures.addCallback(outputFuture, new FutureCallback<>() { 77 | @Override 78 | public void onSuccess(final RpcResult result) { 79 | final NormalizedNode domOutput = StartActionProcessor.this.adapterSerializer 80 | .toNormalizedNodeActionOutput(Start.class, result.getResult()); 81 | final List list = new ArrayList<>(); 82 | list.add(domOutput); 83 | completableFuture.complete(new ResponseData(list)); 84 | } 85 | 86 | @Override 87 | public void onFailure(final Throwable throwable) { 88 | LOG.error("{} action cannot be invoked.", startAction, throwable); 89 | } 90 | }, Executors.newSingleThreadExecutor()); 91 | return completableFuture; 92 | } catch (final TransformerException | DocumentedException | DeserializationException e) { 93 | throw new RuntimeException(e); 94 | } 95 | } 96 | 97 | @Override 98 | protected ActionDefinition getActionDefinition() { 99 | return this.definition; 100 | } 101 | 102 | @Override 103 | protected Absolute getActionPath() { 104 | return this.path; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/src/test/resources/get_schemas_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/src/test/resources/reset_action_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | server-earth 5 | 6 | 2020-09-03T16:20:00Z 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/devices/lighty-actions-device/src/test/resources/start_action_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2020-09-03T16:30:00Z 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | 15 | io.lighty.netconf.device.examples 16 | examples-parent 17 | 22.0.0-SNAPSHOT 18 | ../../parents/examples-parent/pom.xml 19 | 20 | 21 | lighty-network-topology-device 22 | jar 23 | 24 | 25 | io.lighty.netconf.device.topology.Main 26 | true 27 | lighty-network-topology-device 28 | lighty-network-topology-device-${project.version} 29 | ${lighty.app.name}-bin.zip 30 | ${lighty.app.name}.jar 31 | 32 | 33 | 34 | 35 | io.lighty.netconf.device.examples.models 36 | lighty-example-network-topology-device-model 37 | 38 | 39 | io.lighty.netconf.device 40 | lighty-netconf-device 41 | 42 | 43 | com.github.spotbugs 44 | spotbugs-annotations 45 | 46 | 47 | 48 | org.junit.jupiter 49 | junit-jupiter-api 50 | test 51 | 52 | 53 | org.junit.jupiter 54 | junit-jupiter-engine 55 | test 56 | 57 | 58 | org.xmlunit 59 | xmlunit-core 60 | test 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/assembly/resources/start-device.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The script accepts one parameter signifying the listening port of the NETCONF server. 4 | # 5 | # ./start-device 6 | # 7 | # When run without a parameter a default port 17830 will be used. 8 | 9 | CLASSPATH=lighty-network-topology-device-22.0.0-SNAPSHOT.jar 10 | 11 | for jar in `ls -1 lib/`; 12 | do 13 | CLASSPATH=$CLASSPATH:lib/$jar 14 | done 15 | 16 | #echo $CLASSPATH 17 | java -server -Xms16M -Xmx40M -XX:MaxMetaspaceSize=40m -classpath $CLASSPATH io.lighty.netconf.device.topology.Main $1 18 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/datastore/DataTreeChangeListenerActivator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.datastore; 9 | 10 | import io.lighty.netconf.device.requests.notification.NotificationPublishService; 11 | import org.opendaylight.mdsal.binding.api.DataBroker; 12 | import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; 13 | import org.opendaylight.mdsal.common.api.LogicalDatastoreType; 14 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; 15 | import org.opendaylight.yangtools.concepts.Registration; 16 | import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | public final class DataTreeChangeListenerActivator { 21 | 22 | private static final Logger LOG = LoggerFactory.getLogger(DataTreeChangeListenerActivator.class); 23 | private static final InstanceIdentifier TOPOLOGY_II = 24 | InstanceIdentifier.create(NetworkTopology.class); 25 | 26 | private final DataBroker dataBroker; 27 | private final NotificationPublishService notificationPublishService; 28 | private Registration dataTreeChangeListenerRegistration; 29 | 30 | public DataTreeChangeListenerActivator(final NotificationPublishService notificationPublishService, 31 | final DataBroker dataBroker) { 32 | this.notificationPublishService = notificationPublishService; 33 | this.dataBroker = dataBroker; 34 | } 35 | 36 | public void init() { 37 | TopologyDataTreeChangeListener topologyDataTreeChangeListener = 38 | new TopologyDataTreeChangeListener(notificationPublishService); 39 | dataTreeChangeListenerRegistration = 40 | dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION, 41 | TOPOLOGY_II), topologyDataTreeChangeListener); 42 | 43 | LOG.info("Data tree change listener registered"); 44 | } 45 | 46 | public void close() { 47 | dataTreeChangeListenerRegistration.close(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/datastore/TopologyDataTreeChangeListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.datastore; 9 | 10 | import io.lighty.netconf.device.requests.notification.NotificationPublishService; 11 | import java.util.HashSet; 12 | import java.util.List; 13 | import java.util.Set; 14 | import org.eclipse.jdt.annotation.NonNull; 15 | import org.opendaylight.mdsal.binding.api.DataObjectModification; 16 | import org.opendaylight.mdsal.binding.api.DataTreeChangeListener; 17 | import org.opendaylight.mdsal.binding.api.DataTreeModification; 18 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; 19 | import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; 20 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.NewTopologyCreated; 21 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.NewTopologyCreatedBuilder; 22 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.TopologyDeleted; 23 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.TopologyDeletedBuilder; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | final class TopologyDataTreeChangeListener implements DataTreeChangeListener { 28 | 29 | private static final Logger LOG = LoggerFactory.getLogger(TopologyDataTreeChangeListener.class); 30 | 31 | private final NotificationPublishService notificationPublishService; 32 | 33 | TopologyDataTreeChangeListener(NotificationPublishService notificationPublishService) { 34 | this.notificationPublishService = notificationPublishService; 35 | } 36 | 37 | @Override 38 | public void onDataTreeChanged(@NonNull List> changes) { 39 | changes.stream().forEach(change -> { 40 | DataObjectModification.ModificationType modificationType = change.getRootNode().getModificationType(); 41 | Set ids = new HashSet<>(); 42 | final NetworkTopology dataBefore = change.getRootNode().getDataBefore(); 43 | final NetworkTopology dataAfter = change.getRootNode().getDataAfter(); 44 | if (DataObjectModification.ModificationType.DELETE.equals(modificationType)) { 45 | 46 | LOG.info("Data has been deleted"); 47 | 48 | notificationForDeletedData(dataBefore, dataAfter, ids); 49 | } else if (DataObjectModification.ModificationType.SUBTREE_MODIFIED.equals(modificationType) 50 | || DataObjectModification.ModificationType.WRITE.equals(modificationType)) { 51 | 52 | int sizeOfDataBefore = 0; 53 | int sizeOfDataAfter = 0; 54 | 55 | if (dataBefore != null) { 56 | sizeOfDataBefore = dataBefore.getTopology().size(); 57 | } 58 | 59 | if (dataAfter != null) { 60 | sizeOfDataAfter = dataAfter.getTopology().size(); 61 | } 62 | 63 | if (sizeOfDataBefore < sizeOfDataAfter) { 64 | LOG.info("Data has been created"); 65 | if (dataBefore != null) { 66 | dataBefore.nonnullTopology().values().forEach(topology -> ids.add(topology.getTopologyId())); 67 | } 68 | 69 | if (dataAfter != null) { 70 | dataAfter.nonnullTopology().values().forEach(topology -> { 71 | if (!ids.contains(topology.getTopologyId())) { 72 | notificationPublishService.publish(new NewTopologyCreatedBuilder() 73 | .setTopologyId(topology.getTopologyId()) 74 | .build(), NewTopologyCreated.QNAME); 75 | } 76 | }); 77 | } 78 | } else { 79 | LOG.info("Data has been modified"); 80 | notificationForDeletedData(dataBefore, dataAfter, ids); 81 | } 82 | } 83 | }); 84 | } 85 | 86 | private void notificationForDeletedData(final NetworkTopology dataBefore, final NetworkTopology dataAfter, 87 | final Set ids) { 88 | if (dataBefore != null) { 89 | dataBefore.nonnullTopology().values().forEach(topology -> ids.add(topology.getTopologyId())); 90 | } 91 | if (dataAfter != null) { 92 | dataAfter.nonnullTopology().values().forEach(topology -> ids.remove(topology.getTopologyId())); 93 | } 94 | if (ids.iterator().hasNext()) { 95 | notificationPublishService.publish(new TopologyDeletedBuilder() 96 | .setTopologyIds(new HashSet<>(ids)) 97 | .build(), TopologyDeleted.QNAME); 98 | } 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/EmptyInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import org.opendaylight.yangtools.binding.DataObject; 11 | 12 | public interface EmptyInput extends DataObject { 13 | } -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceAbstractProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.codecs.util.XmlNodeConverter; 12 | import io.lighty.codecs.util.exception.DeserializationException; 13 | import io.lighty.netconf.device.NetconfDeviceServices; 14 | import io.lighty.netconf.device.requests.RpcOutputRequestProcessor; 15 | import io.lighty.netconf.device.response.Response; 16 | import io.lighty.netconf.device.response.ResponseData; 17 | import io.lighty.netconf.device.utils.RPCUtil; 18 | import io.lighty.netconf.device.utils.TimeoutUtil; 19 | import java.io.IOException; 20 | import java.io.Reader; 21 | import java.util.Collections; 22 | import java.util.concurrent.CompletableFuture; 23 | import java.util.concurrent.ExecutionException; 24 | import java.util.concurrent.TimeUnit; 25 | import java.util.concurrent.TimeoutException; 26 | import javax.xml.transform.TransformerException; 27 | import org.opendaylight.mdsal.binding.dom.adapter.ConstantAdapterContext; 28 | import org.opendaylight.mdsal.binding.dom.adapter.CurrentAdapterSerializer; 29 | import org.opendaylight.yangtools.binding.DataObject; 30 | import org.opendaylight.yangtools.yang.common.RpcResult; 31 | import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; 32 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 33 | import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; 34 | import org.slf4j.Logger; 35 | import org.slf4j.LoggerFactory; 36 | import org.w3c.dom.Element; 37 | 38 | public abstract class NetworkTopologyServiceAbstractProcessor 39 | extends RpcOutputRequestProcessor { 40 | 41 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceAbstractProcessor.class); 42 | private CurrentAdapterSerializer adapterSerializer; 43 | 44 | @Override 45 | public void init(final NetconfDeviceServices netconfDeviceServices) { 46 | super.init(netconfDeviceServices); 47 | final ConstantAdapterContext constantAdapterContext 48 | = new ConstantAdapterContext(netconfDeviceServices.getAdapterContext().currentSerializer()); 49 | this.adapterSerializer = constantAdapterContext.currentSerializer(); 50 | } 51 | 52 | @Override 53 | protected CompletableFuture execute(final Element requestXmlElement) { 54 | try (Reader readerFromElement = RPCUtil.createReaderFromElement(requestXmlElement)) { 55 | final XmlNodeConverter xmlNodeConverter = getNetconfDeviceServices().getXmlNodeConverter(); 56 | 57 | //1. convert XML input into NormalizedNode 58 | 59 | final NormalizedNode deserializedNode = xmlNodeConverter.deserialize( 60 | Absolute.of(getRpcDefinition().getQName(), getRpcDefinition().getInput().getQName()), 61 | readerFromElement); 62 | 63 | //2. convert NormalizedNode into RPC input 64 | final T input = convertToBindingAwareRpc(getRpcDefInputAbsolutePath(), (ContainerNode) deserializedNode); 65 | 66 | //3. invoke RPC 67 | final ListenableFuture> invokeRpc = invoke(input); 68 | final RpcResult rpcResult = invokeRpc.get(TimeoutUtil.TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 69 | 70 | //4. convert RPC output to ContainerNode 71 | final ContainerNode containerNode = this.adapterSerializer.toNormalizedNodeRpcData(rpcResult.getResult()); 72 | 73 | //5. create response 74 | final ResponseData responseData; 75 | if (containerNode.body().isEmpty()) { 76 | responseData = new ResponseData(Collections.emptyList()); 77 | } else { 78 | responseData = new ResponseData(Collections.singletonList(containerNode)); 79 | } 80 | return CompletableFuture.completedFuture(responseData); 81 | } catch (final ExecutionException | DeserializationException | TransformerException 82 | | TimeoutException | IOException e) { 83 | LOG.error("Error while executing RPC", e); 84 | return CompletableFuture.failedFuture(e); 85 | } catch (final InterruptedException e) { 86 | LOG.error("Interrupted while executing RPC", e); 87 | Thread.currentThread().interrupt(); 88 | return CompletableFuture.failedFuture(e); 89 | } 90 | } 91 | 92 | protected abstract ListenableFuture> invoke(T input); 93 | 94 | @SuppressWarnings("unchecked") 95 | public T convertToBindingAwareRpc(final Absolute absolute, final ContainerNode rpcData) { 96 | return (T) this.adapterSerializer.fromNormalizedNodeRpcData(absolute, rpcData); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceAddNodeToTopologyProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.topology.rpcs.NetworkTopologyServiceImpl; 12 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.AddNodeIntoTopology; 13 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.AddNodeIntoTopologyInput; 14 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.AddNodeIntoTopologyOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class NetworkTopologyServiceAddNodeToTopologyProcessor extends 22 | NetworkTopologyServiceAbstractProcessor 23 | implements AddNodeIntoTopology { 24 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceAddNodeToTopologyProcessor.class); 25 | 26 | private final NetworkTopologyServiceImpl networkTopologyRpcsService; 27 | private final QName qName = QName.create("urn:tech.pantheon.netconfdevice.network.topology.rpcs", 28 | "add-node-into-topology"); 29 | 30 | public NetworkTopologyServiceAddNodeToTopologyProcessor( 31 | final NetworkTopologyServiceImpl networkTopologyRpcsService) { 32 | this.networkTopologyRpcsService = networkTopologyRpcsService; 33 | } 34 | 35 | @Override 36 | public QName getIdentifier() { 37 | return this.qName; 38 | } 39 | 40 | 41 | @Override 42 | public ListenableFuture> invoke(final AddNodeIntoTopologyInput input) { 43 | return networkTopologyRpcsService.addNodeIntoTopology(input); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceCreateTopologyProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.topology.rpcs.NetworkTopologyServiceImpl; 12 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.CreateTopology; 13 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.CreateTopologyInput; 14 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.CreateTopologyOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class NetworkTopologyServiceCreateTopologyProcessor extends 22 | NetworkTopologyServiceAbstractProcessor 23 | implements CreateTopology { 24 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceCreateTopologyProcessor.class); 25 | 26 | private final NetworkTopologyServiceImpl networkTopologyRpcsService; 27 | private final QName qName = QName.create("urn:tech.pantheon.netconfdevice.network.topology.rpcs", 28 | "create-topology"); 29 | 30 | public NetworkTopologyServiceCreateTopologyProcessor(final NetworkTopologyServiceImpl networkTopologyRpcsService) { 31 | this.networkTopologyRpcsService = networkTopologyRpcsService; 32 | } 33 | 34 | @Override 35 | public QName getIdentifier() { 36 | return this.qName; 37 | } 38 | 39 | @Override 40 | public ListenableFuture> invoke(final CreateTopologyInput input) { 41 | return networkTopologyRpcsService.createTopology(input); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceGetNodeFromTopologyProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.topology.rpcs.NetworkTopologyServiceImpl; 12 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetNodeFromTopologyById; 13 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetNodeFromTopologyByIdInput; 14 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetNodeFromTopologyByIdOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class NetworkTopologyServiceGetNodeFromTopologyProcessor extends 22 | NetworkTopologyServiceAbstractProcessor 23 | implements GetNodeFromTopologyById { 24 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceGetNodeFromTopologyProcessor.class); 25 | 26 | private final NetworkTopologyServiceImpl networkTopologyRpcsService; 27 | private final QName qName = QName.create("urn:tech.pantheon.netconfdevice.network.topology.rpcs", 28 | "get-node-from-topology-by-id"); 29 | 30 | public NetworkTopologyServiceGetNodeFromTopologyProcessor(final NetworkTopologyServiceImpl networkTopologyService) { 31 | this.networkTopologyRpcsService = networkTopologyService; 32 | } 33 | 34 | @Override 35 | public QName getIdentifier() { 36 | return qName; 37 | } 38 | 39 | 40 | @Override 41 | public ListenableFuture> invoke(final GetNodeFromTopologyByIdInput input) { 42 | return networkTopologyRpcsService.getNodeFromTopologyById(input); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceGetTopologiesProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.topology.rpcs.NetworkTopologyServiceImpl; 12 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetTopologies; 13 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetTopologiesInput; 14 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetTopologiesOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class NetworkTopologyServiceGetTopologiesProcessor extends NetworkTopologyServiceAbstractProcessor< 22 | GetTopologiesInput, GetTopologiesOutput> implements GetTopologies { 23 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceGetTopologiesProcessor.class); 24 | 25 | private final NetworkTopologyServiceImpl networkTopologyRpcsService; 26 | private final QName qName = QName.create("urn:tech.pantheon.netconfdevice.network.topology.rpcs", 27 | "get-topologies"); 28 | 29 | public NetworkTopologyServiceGetTopologiesProcessor(final NetworkTopologyServiceImpl networkTopologyRpcsService) { 30 | this.networkTopologyRpcsService = networkTopologyRpcsService; 31 | } 32 | 33 | @Override 34 | public QName getIdentifier() { 35 | return this.qName; 36 | } 37 | 38 | @Override 39 | public ListenableFuture> invoke(final GetTopologiesInput input) { 40 | return networkTopologyRpcsService.getTopologies(input); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceGetTopologyByIdProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.topology.rpcs.NetworkTopologyServiceImpl; 12 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetTopologyById; 13 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetTopologyByIdInput; 14 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetTopologyByIdOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class NetworkTopologyServiceGetTopologyByIdProcessor extends 22 | NetworkTopologyServiceAbstractProcessor 23 | implements GetTopologyById { 24 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceGetTopologyByIdProcessor.class); 25 | 26 | private final NetworkTopologyServiceImpl networkTopologyRpcsService; 27 | private final QName qName = QName.create("urn:tech.pantheon.netconfdevice.network.topology.rpcs", 28 | "get-topology-by-id"); 29 | 30 | public NetworkTopologyServiceGetTopologyByIdProcessor(final NetworkTopologyServiceImpl networkTopologyRpcsService) { 31 | this.networkTopologyRpcsService = networkTopologyRpcsService; 32 | } 33 | 34 | @Override 35 | public QName getIdentifier() { 36 | return qName; 37 | } 38 | 39 | @Override 40 | public ListenableFuture> invoke(final GetTopologyByIdInput input) { 41 | return networkTopologyRpcsService.getTopologyById(input); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceGetTopologyIdsProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.topology.rpcs.NetworkTopologyServiceImpl; 12 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetTopologyIds; 13 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetTopologyIdsInput; 14 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.GetTopologyIdsOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class NetworkTopologyServiceGetTopologyIdsProcessor extends NetworkTopologyServiceAbstractProcessor< 22 | GetTopologyIdsInput, GetTopologyIdsOutput> implements GetTopologyIds { 23 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceGetTopologyIdsProcessor.class); 24 | 25 | private final NetworkTopologyServiceImpl networkTopologyRpcsService; 26 | private final QName qName = QName.create("urn:tech.pantheon.netconfdevice.network.topology.rpcs", 27 | "get-topology-ids"); 28 | 29 | public NetworkTopologyServiceGetTopologyIdsProcessor(final NetworkTopologyServiceImpl networkTopologyRpcsService) { 30 | this.networkTopologyRpcsService = networkTopologyRpcsService; 31 | } 32 | 33 | @Override 34 | public QName getIdentifier() { 35 | return this.qName; 36 | } 37 | 38 | @Override 39 | public ListenableFuture> invoke(final GetTopologyIdsInput input) { 40 | return networkTopologyRpcsService.getTopologyIds(input); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceRemoveAllTopologiesProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.topology.rpcs.NetworkTopologyServiceImpl; 12 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.RemoveAllTopologies; 13 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.RemoveAllTopologiesInput; 14 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.RemoveAllTopologiesOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class NetworkTopologyServiceRemoveAllTopologiesProcessor extends NetworkTopologyServiceAbstractProcessor< 22 | RemoveAllTopologiesInput, RemoveAllTopologiesOutput> implements RemoveAllTopologies { 23 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceRemoveAllTopologiesProcessor.class); 24 | 25 | private final NetworkTopologyServiceImpl networkTopologyRpcsService; 26 | private final QName qName = QName.create("urn:tech.pantheon.netconfdevice.network.topology.rpcs", 27 | "remove-all-topologies"); 28 | 29 | public NetworkTopologyServiceRemoveAllTopologiesProcessor( 30 | final NetworkTopologyServiceImpl networkTopologyRpcsService) { 31 | this.networkTopologyRpcsService = networkTopologyRpcsService; 32 | } 33 | 34 | @Override 35 | public QName getIdentifier() { 36 | return this.qName; 37 | } 38 | 39 | @Override 40 | public ListenableFuture> invoke(final RemoveAllTopologiesInput input) { 41 | return networkTopologyRpcsService.removeAllTopologies(input); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceRemoveNodeProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.topology.rpcs.NetworkTopologyServiceImpl; 12 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.RemoveNodeFromTopology; 13 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.RemoveNodeFromTopologyInput; 14 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.RemoveNodeFromTopologyOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class NetworkTopologyServiceRemoveNodeProcessor extends 22 | NetworkTopologyServiceAbstractProcessor 23 | implements RemoveNodeFromTopology { 24 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceRemoveNodeProcessor.class); 25 | 26 | private final NetworkTopologyServiceImpl networkTopologyRpcsService; 27 | private final QName qName = QName.create("urn:tech.pantheon.netconfdevice.network.topology.rpcs", 28 | "remove-node-from-topology"); 29 | 30 | public NetworkTopologyServiceRemoveNodeProcessor(final NetworkTopologyServiceImpl networkTopologyRpcsService) { 31 | this.networkTopologyRpcsService = networkTopologyRpcsService; 32 | } 33 | 34 | @Override 35 | public QName getIdentifier() { 36 | return this.qName; 37 | } 38 | 39 | @Override 40 | public ListenableFuture> invoke(final RemoveNodeFromTopologyInput input) { 41 | return networkTopologyRpcsService.removeNodeFromTopology(input); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/java/io/lighty/netconf/device/topology/processors/NetworkTopologyServiceRemoveTopologyProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.topology.rpcs.NetworkTopologyServiceImpl; 12 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.RemoveTopology; 13 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.RemoveTopologyInput; 14 | import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev230927.RemoveTopologyOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class NetworkTopologyServiceRemoveTopologyProcessor extends 22 | NetworkTopologyServiceAbstractProcessor 23 | implements RemoveTopology { 24 | private static final Logger LOG = LoggerFactory.getLogger(NetworkTopologyServiceRemoveTopologyProcessor.class); 25 | 26 | private final NetworkTopologyServiceImpl networkTopologyRpcsService; 27 | private final QName qName = QName.create("urn:tech.pantheon.netconfdevice.network.topology.rpcs", 28 | "remove-topology"); 29 | 30 | public NetworkTopologyServiceRemoveTopologyProcessor(final NetworkTopologyServiceImpl networkTopologyRpcsService) { 31 | this.networkTopologyRpcsService = networkTopologyRpcsService; 32 | } 33 | 34 | @Override 35 | public QName getIdentifier() { 36 | return this.qName; 37 | } 38 | 39 | @Override 40 | public ListenableFuture> invoke(final RemoveTopologyInput input) { 41 | return networkTopologyRpcsService.removeTopology(input); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/resources/initial-network-topo-config-datastore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | default-topology 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/main/resources/initial-network-topo-operational-datastore.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANTHEONtech/lighty-netconf-simulator/ba27100fd12b874fc8fb53455443ecdfbe63f172/examples/devices/lighty-network-topology-device/src/main/resources/initial-network-topo-operational-datastore.xml -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/java/io/lighty/netconf/device/topology/TestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.topology; 9 | 10 | import java.io.File; 11 | import java.io.FileInputStream; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.net.URISyntaxException; 15 | import java.net.URL; 16 | import java.util.Objects; 17 | 18 | public final class TestUtils { 19 | 20 | private TestUtils() { 21 | } 22 | 23 | public static InputStream xmlFileToInputStream(final String fileName) throws URISyntaxException, IOException { 24 | final URL getRequest = DeviceTest.class.getClassLoader().getResource(fileName); 25 | return new FileInputStream(new File(Objects.requireNonNull(getRequest).toURI())); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/add_node_rpc_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | test-topology 4 | 5 | test-nettopo-node 6 | 127.0.0.1 7 | 17835 8 | 9 | admin 10 | admin 11 | 12 | false 13 | 0 14 | false 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/add_node_rpc_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/create_topology_config_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | test-config-topology 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/create_topology_rpc_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | test-topology 4 | 5 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/create_topology_rpc_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/delete_topology_config_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | test-config-topology 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/delete_topology_rpc_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | test-topology 4 | 5 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/delete_topology_rpc_response.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/get_config_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/get_schemas_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/devices/lighty-network-topology-device/src/test/resources/merge_topology_config_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | test-config-topology-merge 10 | 11 | test-nettopo-node 12 | 13 | 17835 14 | 15 | admin 16 | admin 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/devices/lighty-notifications-device/README.md: -------------------------------------------------------------------------------- 1 | # Notification device example 2 | This NETCONF device example shows how NETCONF device is customized to publish notifications from the device. Device uses `lighty-test-notifications@2018-08-20.yang` YANG model located in `examples/models/lighty-example-notifications-model`. Therefore, the name: notifications device. 3 | 4 | ### Usage 5 | Device uses `TriggerNotificationProcessor` class to handle incoming `triggerDataNotification` RPC which implies publishing notification `DataNotification`. 6 | `triggerDataNotification` RPC and `dataNotification` notification are described in YANG file. 7 | Check commands in [Notifications device model](#notifications-device-model) on how to trigger publishing `dataNotification` notification. 8 | 9 | ### Build and run 10 | Build root project - for more details check: [README](../../../README.md) 11 | 12 | **Run device** 13 | * extract binary distribution `lighty-notifications-device-22.0.0-SNAPSHOT-bin.zip` 14 | from target directory 15 | * run jar file from zip with default parameter 16 | ``` 17 | java -jar lighty-notifications-device-22.0.0-SNAPSHOT.jar 18 | ``` 19 | To run device on specific port, add port number as an argument 20 | * run device on specific port `12345` (any available port) 21 | ``` 22 | java -jar lighty-notifications-device-22.0.0-SNAPSHOT.jar 12345 23 | ``` 24 | 25 | ### Connect to device via SSH 26 | **Open session** 27 | 28 | To connect to a device via SSH, run command 29 | 30 | ``` 31 | ssh admin@127.0.0.1 -p 12345 -s netconf 32 | ``` 33 | 34 | where 35 | - `admin` is default username of a device with password `admin`(no other users) 36 | - `127.0.0.1` is the local IP address of the machine where device is running 37 | - `-p 12345` is port number of running device, default is `17830` 38 | - `-s netconf` option establishes the NETCONF session as an SSH subsystem, 39 | which means that NETCONF can be used in terminal through opened SSH session 40 | 41 | To complete connection with a device, it is necessary to initiate handshake by 42 | sending client's model capabilities in hello-message: 43 | 44 | ``` 45 | 46 | 47 | urn:ietf:params:netconf:base:1.0 48 | 49 | 50 | ]]>]]> 51 | ``` 52 | which informs the device which capabilities the client supports. 53 | The capabilities tag contains list of capabilities the client supports, e.g. 54 | ``` 55 | 56 | 57 | capability1 58 | capability2 59 | capability3 60 | ... 61 | 62 | 63 | ]]>]]> 64 | ``` 65 | 66 | If handshake is not completed by sending hello message with client's capabilities 67 | and any other message is sent, following error message is received (long text replaced with ...): 68 | ``` 69 | 70 | 71 | 72 | rpc 73 | malformed-message 74 | error 75 | 76 | java.lang.IllegalStateException: Hello message not received, instead received: ... 77 | 78 | 79 | 80 | java.lang.IllegalStateException: Hello message not received, instead received: ... 81 | 82 | 83 | 84 | 85 | ]]>]]> 86 | ``` 87 | 88 | **Close session** 89 | 90 | To properly exit current NETCONF device SSH session, close-session message 91 | needs to be send 92 | ``` 93 | 94 | 95 | 96 | ]]>]]> 97 | ``` 98 | `ok` message will be replied and then closed the session. 99 | ``` 100 | 101 | 102 | 103 | 104 | ``` 105 | 106 | ### Basic NETCONF commands 107 | 108 | Notification device supports all basic NETCONF commands, 109 | but as far as this device does not contain any other YANG model with root containers, 110 | this device will not be able to store or modified data device manages. 111 | This device tries to describe usage of NETCONF `notifications`, only. 112 | For detailed description, find more details in topology-device or toaster-device projects. 113 | 114 | ### Trigger and receive notification 115 | YANG model used by the device is `lighty-test-notifications@2018-08-20.yang`. 116 | 117 | Notifications device has only one RPC defined in YANG model: 118 | 119 | **triggerDataNotification** 120 | 121 | - takes 4 mandatory parameters: `ClientId`, `Count`, `Delay` and `Payload` 122 | 123 | To trigger RPC with 124 | client `ClientId: 0`, `Count: 5`, `Delay: 500` and `Payload: just simple notification`, 125 | call `triggerDataNotification` RPC 126 | 127 | ``` 128 | 129 | 130 | 0 131 | 5 132 | 500 133 | just simple notification 134 | 135 | 136 | ]]>]]> 137 | ``` 138 | 139 | Log info message after triggering `triggerDataNotification RPC`: 140 | `INFO [nioEventLoopGroup-2-3] (TriggerNotificationProcessor.java:82) - triggering notifications: clientId=0 5 delay=500ms, payload=just simple notification` 141 | `INFO [nioEventLoopGroup-2-3] (TriggerNotificationProcessor.java:71) - sending notification clientId=0 1/5` 142 | 143 | Triggered `triggerDataNotification` RPC publishes notification `DataNotification`, 144 | so any other listener device subscribed to notifications by `create-subscription` message, 145 | will receive notification message, example: 146 | ``` 147 | 148 | 149 | 2020-09-04T14:56:15Z 150 | 151 | 5 152 | just simple notification 153 | 0 154 | 155 | 156 | ]]>]]> 157 | ``` 158 | 159 | which contains input parameters of called `triggerDataNotification` RPC, 160 | in this case `Ordinal(Count): 5`, `ClientId: 0` and `Payload: just simple notification`. 161 | 162 | **Subscribe on notification** 163 | 164 | To receive notifications on NETCONF listener device, subscribe 165 | for notification by sending `create-subscription` message: 166 | 167 | ``` 168 | 169 | 170 | 171 | 172 | ]]>]]> 173 | ``` 174 | -------------------------------------------------------------------------------- /examples/devices/lighty-notifications-device/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | 15 | io.lighty.netconf.device.examples 16 | examples-parent 17 | 22.0.0-SNAPSHOT 18 | ../../parents/examples-parent/pom.xml 19 | 20 | 21 | lighty-notifications-device 22 | jar 23 | 24 | 25 | io.lighty.netconf.device.notification.Main 26 | true 27 | 28 | 29 | 30 | 31 | io.lighty.netconf.device.examples.models 32 | lighty-example-notifications-model 33 | 34 | 35 | io.lighty.netconf.device 36 | lighty-netconf-device 37 | 38 | 39 | org.junit.jupiter 40 | junit-jupiter-api 41 | test 42 | 43 | 44 | org.junit.jupiter 45 | junit-jupiter-engine 46 | test 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/devices/lighty-notifications-device/src/assembly/resources/start-device.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The script accepts one parameter signifying the listening port of the NETCONF server. 4 | # 5 | # ./start-device 6 | # 7 | # When run without a parameter a default port 17830 will be used. 8 | 9 | CLASSPATH=lighty-notifications-device-22.0.0-SNAPSHOT.jar 10 | 11 | for jar in `ls -1 lib/`; 12 | do 13 | CLASSPATH=$CLASSPATH:lib/$jar 14 | done 15 | 16 | #echo $CLASSPATH 17 | java -server -Xms16M -Xmx40M -XX:MaxMetaspaceSize=40m -classpath $CLASSPATH io.lighty.netconf.device.notification.Main $1 18 | -------------------------------------------------------------------------------- /examples/devices/lighty-notifications-device/src/main/java/io/lighty/netconf/device/notification/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.notification; 9 | 10 | import com.google.common.collect.ImmutableSet; 11 | import io.lighty.netconf.device.NetconfDevice; 12 | import io.lighty.netconf.device.NetconfDeviceBuilder; 13 | import io.lighty.netconf.device.notification.processors.TriggerNotificationProcessor; 14 | import java.util.Set; 15 | import org.opendaylight.yangtools.binding.meta.YangModuleInfo; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | public class Main { 20 | private static final Logger LOG = LoggerFactory.getLogger(Main.class); 21 | private static final Set NOTIFICATION_MODEL_PATHS = ImmutableSet.of( 22 | org.opendaylight.yang.svc.v1.yang.lighty.test.notifications.rev180820.YangModuleInfoImpl.getInstance() 23 | ); 24 | 25 | private ShutdownHook shutdownHook; 26 | 27 | public static void main(final String[] args) { 28 | final Main app = new Main(); 29 | app.start(args, true); 30 | } 31 | 32 | public void start(final String[] args) { 33 | start(args, false); 34 | } 35 | 36 | public void start(final String[] args, final boolean registerShutdownHook) { 37 | final int port = getPortFromArgs(args); 38 | final TriggerNotificationProcessor triggerNotificationProcessor = new TriggerNotificationProcessor(); 39 | final NetconfDevice netconfDevice = new NetconfDeviceBuilder() 40 | .setCredentials("admin", "admin") 41 | .setBindingPort(port) 42 | .withModels(NOTIFICATION_MODEL_PATHS) 43 | .withDefaultRequestProcessors() 44 | .withDefaultCapabilities() 45 | .withRequestProcessor(triggerNotificationProcessor) 46 | .withDefaultNotificationProcessor() 47 | .build(); 48 | triggerNotificationProcessor.init(netconfDevice.getNetconfDeviceServices().getNotificationPublishService()); 49 | netconfDevice.start(); 50 | this.shutdownHook = new ShutdownHook(netconfDevice); 51 | if (registerShutdownHook) { 52 | Runtime.getRuntime().addShutdownHook(this.shutdownHook); 53 | } 54 | } 55 | 56 | public void shutdown() { 57 | if (this.shutdownHook != null) { 58 | this.shutdownHook.execute(); 59 | } 60 | } 61 | 62 | private static class ShutdownHook extends Thread { 63 | 64 | private final NetconfDevice netConfDevice; 65 | 66 | ShutdownHook(final NetconfDevice netConfDevice) { 67 | this.netConfDevice = netConfDevice; 68 | } 69 | 70 | @Override 71 | public void run() { 72 | this.execute(); 73 | } 74 | 75 | @SuppressWarnings("checkstyle:IllegalCatch") 76 | public void execute() { 77 | LOG.info("Shutting down Lighty-Notification device."); 78 | if (this.netConfDevice != null) { 79 | try { 80 | this.netConfDevice.close(); 81 | } catch (final Exception e) { 82 | LOG.error("Failed to close Netconf device properly {}", e.getMessage()); 83 | } 84 | } 85 | } 86 | } 87 | 88 | @SuppressWarnings("checkstyle:IllegalCatch") 89 | private static int getPortFromArgs(final String[] args) { 90 | try { 91 | return Integer.parseInt(args[0]); 92 | } catch (final Exception e) { 93 | return 17830; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /examples/devices/lighty-notifications-device/src/main/java/io/lighty/netconf/device/notification/processors/TriggerNotificationProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.notification.processors; 9 | 10 | import io.lighty.codecs.util.XmlNodeConverter; 11 | import io.lighty.codecs.util.exception.DeserializationException; 12 | import io.lighty.netconf.device.requests.RpcOutputRequestProcessor; 13 | import io.lighty.netconf.device.requests.notification.NotificationPublishService; 14 | import io.lighty.netconf.device.response.Response; 15 | import io.lighty.netconf.device.response.ResponseData; 16 | import io.lighty.netconf.device.utils.RPCUtil; 17 | import java.io.IOException; 18 | import java.io.Reader; 19 | import java.util.Collections; 20 | import java.util.concurrent.CompletableFuture; 21 | import javax.xml.transform.TransformerException; 22 | import org.opendaylight.mdsal.binding.dom.adapter.ConstantAdapterContext; 23 | import org.opendaylight.mdsal.binding.dom.adapter.CurrentAdapterSerializer; 24 | import org.opendaylight.yang.gen.v1.yang.lighty.test.notifications.rev180820.DataNotification; 25 | import org.opendaylight.yang.gen.v1.yang.lighty.test.notifications.rev180820.DataNotificationBuilder; 26 | import org.opendaylight.yang.gen.v1.yang.lighty.test.notifications.rev180820.TriggerDataNotificationInput; 27 | import org.opendaylight.yangtools.binding.DataObject; 28 | import org.opendaylight.yangtools.yang.common.QName; 29 | import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; 30 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 31 | import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; 32 | import org.slf4j.Logger; 33 | import org.slf4j.LoggerFactory; 34 | import org.w3c.dom.Element; 35 | 36 | /** 37 | * Class is processing rpc requests, currently its looking for triggerDataNotification rpc only. 38 | * When the rpc is triggered execute method is called. Using device notification publish service to pass to 39 | * LightyTriggerNotificationsImpl. 40 | */ 41 | @SuppressWarnings("checkstyle:MemberName") 42 | public class TriggerNotificationProcessor extends RpcOutputRequestProcessor { 43 | 44 | private static final Logger LOG = LoggerFactory.getLogger(TriggerNotificationProcessor.class); 45 | 46 | private final QName qName = QName.create("yang:lighty:test:notifications", "triggerDataNotification"); 47 | private NotificationPublishService notificationPublishService; 48 | private CurrentAdapterSerializer adapterSerializer; 49 | 50 | public void init(final NotificationPublishService paramNotificationPublishService) { 51 | this.notificationPublishService = paramNotificationPublishService; 52 | final ConstantAdapterContext constantAdapterContext 53 | = new ConstantAdapterContext(getNetconfDeviceServices().getAdapterContext().currentSerializer()); 54 | this.adapterSerializer = constantAdapterContext.currentSerializer(); 55 | } 56 | 57 | /** 58 | * Converts Xml input element into TriggerDataNotificationInput using DataCodec 59 | * and publish notification. 60 | * 61 | * @param requestXmlElement XML RPC request element 62 | * @return The future result of RPC processing 63 | */ 64 | @Override 65 | protected CompletableFuture execute(final Element requestXmlElement) { 66 | try (Reader readerFromElement = RPCUtil.createReaderFromElement(requestXmlElement)) { 67 | final XmlNodeConverter xmlNodeConverter = getNetconfDeviceServices().getXmlNodeConverter(); 68 | final NormalizedNode deserializedNode = xmlNodeConverter.deserialize( 69 | Absolute.of(getRpcDefinition().getQName(), getRpcDefinition().getInput().getQName()), 70 | readerFromElement); 71 | final DataObject dataObject = this.adapterSerializer 72 | .fromNormalizedNodeRpcData(getRpcDefInputAbsolutePath(), (ContainerNode) deserializedNode); 73 | if (dataObject instanceof TriggerDataNotificationInput) { 74 | final TriggerDataNotificationInput input = (TriggerDataNotificationInput) dataObject; 75 | final DataNotification notification = createNotification(input); 76 | LOG.info("sending notification clientId={} {}/{}", input.getClientId(), 1, input.getCount()); 77 | this.notificationPublishService.publish(notification, DataNotification.QNAME); 78 | return CompletableFuture.completedFuture(new ResponseData(Collections.emptyList())); 79 | } else { 80 | return CompletableFuture.failedFuture(new NotificationProcessorException( 81 | String.format("Expecting TriggerDataNotificationInput inside RPCDefinition, found: [%s]", 82 | dataObject.getClass().toString()))); 83 | } 84 | } catch (final TransformerException | DeserializationException | IOException ex) { 85 | LOG.error("Could not trigger notification, {}", ex.getMessage()); 86 | return CompletableFuture.failedFuture(ex); 87 | } 88 | } 89 | 90 | private DataNotification createNotification(final TriggerDataNotificationInput input) { 91 | LOG.info("triggering notifications: clientId={} {} delay={}ms, payload={}", 92 | input.getClientId(), input.getCount(), input.getDelay(), input.getPayload()); 93 | return new DataNotificationBuilder() 94 | .setClientId(input.getClientId()) 95 | .setOrdinal(input.getCount()) 96 | .setPayload(input.getPayload()) 97 | .build(); 98 | } 99 | 100 | @Override 101 | public QName getIdentifier() { 102 | return this.qName; 103 | } 104 | 105 | public static class NotificationProcessorException extends Exception { 106 | 107 | public NotificationProcessorException(String message) { 108 | super(message); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /examples/devices/lighty-notifications-device/src/test/java/io/lighty/devices/notification/tests/NotificationNetconfSessionListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.devices.notification.tests; 9 | 10 | import java.util.concurrent.CountDownLatch; 11 | import org.opendaylight.netconf.api.messages.NetconfMessage; 12 | import org.opendaylight.netconf.client.NetconfClientSession; 13 | import org.opendaylight.netconf.client.SimpleNetconfClientSessionListener; 14 | 15 | public class NotificationNetconfSessionListener extends SimpleNetconfClientSessionListener { 16 | 17 | private CountDownLatch countDownLatch; 18 | private String expectedPayload; 19 | 20 | public NotificationNetconfSessionListener(CountDownLatch countDownLatch, String expectedPayload) { 21 | this.countDownLatch = countDownLatch; 22 | this.expectedPayload = expectedPayload; 23 | } 24 | 25 | @Override 26 | public synchronized void onMessage(final NetconfClientSession session, final NetconfMessage message) { 27 | super.onMessage(session, message); 28 | if (isNotification(message)) { 29 | if (checkNotificationPayload(message)) { 30 | this.countDownLatch.countDown(); 31 | } 32 | } 33 | } 34 | 35 | private boolean checkNotificationPayload(NetconfMessage message) { 36 | return message.getDocument().getDocumentElement().getElementsByTagName("Payload") 37 | .item(0).getTextContent().equals(this.expectedPayload); 38 | } 39 | 40 | private boolean isNotification(NetconfMessage message) { 41 | return message.getDocument().getDocumentElement().getLocalName().equals("notification"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/devices/lighty-notifications-device/src/test/resources/get_schemas_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/devices/lighty-notifications-device/src/test/resources/subcribe_to_notifications_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /examples/devices/lighty-notifications-device/src/test/resources/trigger_data_notification_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 1 5 | 1000 6 | Test Notification 7 | 8 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | 15 | io.lighty.netconf.device.examples 16 | examples-parent 17 | 22.0.0-SNAPSHOT 18 | ../../parents/examples-parent/pom.xml 19 | 20 | 21 | lighty-toaster-device 22 | jar 23 | 24 | 25 | io.lighty.netconf.device.toaster.Main 26 | true 27 | 28 | 29 | 30 | 31 | io.lighty.models.test 32 | lighty-toaster 33 | compile 34 | 35 | 36 | io.lighty.netconf.device 37 | lighty-netconf-device 38 | 39 | 40 | com.github.spotbugs 41 | spotbugs-annotations 42 | 43 | 44 | 45 | org.junit.jupiter 46 | junit-jupiter-api 47 | test 48 | 49 | 50 | org.junit.jupiter 51 | junit-jupiter-engine 52 | test 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/assembly/resources/start-device.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The script accepts one parameter signifying the listening port of the NETCONF server. 4 | # 5 | # ./start-device 6 | # 7 | # When run without a parameter a default port 17830 will be used. 8 | 9 | CLASSPATH=lighty-toaster-device-22.0.0-SNAPSHOT.jar 10 | 11 | for jar in `ls -1 lib/`; 12 | do 13 | CLASSPATH=$CLASSPATH:lib/$jar 14 | done 15 | 16 | #echo $CLASSPATH 17 | java -server -Xms16M -Xmx40M -XX:MaxMetaspaceSize=40m -classpath $CLASSPATH io.lighty.netconf.device.toaster.Main $1 18 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/main/java/io/lighty/netconf/device/toaster/processors/ToasterServiceAbstractProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.toaster.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.codecs.util.XmlNodeConverter; 12 | import io.lighty.codecs.util.exception.DeserializationException; 13 | import io.lighty.netconf.device.NetconfDeviceServices; 14 | import io.lighty.netconf.device.requests.RpcOutputRequestProcessor; 15 | import io.lighty.netconf.device.response.Response; 16 | import io.lighty.netconf.device.response.ResponseData; 17 | import io.lighty.netconf.device.utils.RPCUtil; 18 | import io.lighty.netconf.device.utils.TimeoutUtil; 19 | import java.io.IOException; 20 | import java.io.Reader; 21 | import java.util.Collections; 22 | import java.util.concurrent.CompletableFuture; 23 | import java.util.concurrent.ExecutionException; 24 | import java.util.concurrent.TimeUnit; 25 | import java.util.concurrent.TimeoutException; 26 | import javax.xml.transform.TransformerException; 27 | import org.opendaylight.mdsal.binding.dom.adapter.ConstantAdapterContext; 28 | import org.opendaylight.mdsal.binding.dom.adapter.CurrentAdapterSerializer; 29 | import org.opendaylight.yangtools.binding.RpcInput; 30 | import org.opendaylight.yangtools.binding.RpcOutput; 31 | import org.opendaylight.yangtools.yang.common.RpcResult; 32 | import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; 33 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 34 | import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; 35 | import org.slf4j.Logger; 36 | import org.slf4j.LoggerFactory; 37 | import org.w3c.dom.Element; 38 | 39 | public abstract class ToasterServiceAbstractProcessor extends 40 | RpcOutputRequestProcessor { 41 | 42 | private static final Logger LOG = LoggerFactory.getLogger(ToasterServiceAbstractProcessor.class); 43 | private CurrentAdapterSerializer adapterSerializer; 44 | 45 | @Override 46 | public void init(final NetconfDeviceServices netconfDeviceServices) { 47 | super.init(netconfDeviceServices); 48 | final ConstantAdapterContext constantAdapterContext 49 | = new ConstantAdapterContext(netconfDeviceServices.getAdapterContext().currentSerializer()); 50 | this.adapterSerializer = constantAdapterContext.currentSerializer(); 51 | } 52 | 53 | @Override 54 | protected CompletableFuture execute(final Element requestXmlElement) { 55 | //1. convert XML input into NormalizedNode 56 | try (Reader readerFromElement = RPCUtil.createReaderFromElement(requestXmlElement);) { 57 | final XmlNodeConverter xmlNodeConverter = getNetconfDeviceServices().getXmlNodeConverter(); 58 | 59 | final NormalizedNode deserializedNode = xmlNodeConverter.deserialize( 60 | Absolute.of(getRpcDefinition().getQName(), getRpcDefinition().getInput().getQName()), 61 | readerFromElement); 62 | 63 | //2. convert NormalizedNode into RPC input 64 | final I input = convertToBindingAwareRpc(getRpcDefInputAbsolutePath(), (ContainerNode) deserializedNode); 65 | 66 | //3. invoke RPC and wait for completion 67 | final ListenableFuture> invokeRpc = invoke(input); 68 | final RpcResult rpcResult = invokeRpc.get(TimeoutUtil.TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 69 | 70 | //4. convert RPC output to ContainerNode 71 | final ContainerNode data = this.adapterSerializer.toNormalizedNodeRpcData(rpcResult.getResult()); 72 | 73 | //5. create response 74 | return CompletableFuture.completedFuture(new ResponseData(Collections.singletonList(data))); 75 | } catch (final ExecutionException | DeserializationException | TransformerException 76 | | TimeoutException | IOException e) { 77 | LOG.error("Error while executing RPC", e); 78 | return CompletableFuture.failedFuture(e); 79 | } catch (final InterruptedException e) { 80 | LOG.error("Interrupted while executing RPC", e); 81 | Thread.currentThread().interrupt(); 82 | return CompletableFuture.failedFuture(e); 83 | } 84 | } 85 | 86 | protected abstract ListenableFuture> invoke(I input); 87 | 88 | @SuppressWarnings("unchecked") 89 | public I convertToBindingAwareRpc(final Absolute absolute, final ContainerNode rpcData) { 90 | return (I) this.adapterSerializer.fromNormalizedNodeRpcData(absolute, rpcData); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/main/java/io/lighty/netconf/device/toaster/processors/ToasterServiceCancelToastProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.toaster.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.toaster.rpcs.ToasterServiceImpl; 12 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToast; 13 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToastInput; 14 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToastOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class ToasterServiceCancelToastProcessor extends ToasterServiceAbstractProcessor implements CancelToast { 23 | 24 | private static final Logger LOG = LoggerFactory.getLogger(ToasterServiceCancelToastProcessor.class); 25 | 26 | private final ToasterServiceImpl toasterService; 27 | private final QName qName = QName.create("http://netconfcentral.org/ns/toaster", "cancel-toast"); 28 | 29 | public ToasterServiceCancelToastProcessor(final ToasterServiceImpl toasterService) { 30 | this.toasterService = toasterService; 31 | } 32 | 33 | @Override 34 | public QName getIdentifier() { 35 | return this.qName; 36 | } 37 | 38 | @Override 39 | public ListenableFuture> invoke(final CancelToastInput input) { 40 | LOG.info("execute RPC: cancel-toast"); 41 | return toasterService.cancelToast(input); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/main/java/io/lighty/netconf/device/toaster/processors/ToasterServiceMakeToastProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.toaster.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.toaster.rpcs.ToasterServiceImpl; 12 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToast; 13 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInput; 14 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class ToasterServiceMakeToastProcessor extends ToasterServiceAbstractProcessor 22 | implements MakeToast { 23 | 24 | private static final Logger LOG = LoggerFactory.getLogger(ToasterServiceMakeToastProcessor.class); 25 | 26 | private final ToasterServiceImpl toasterService; 27 | private final QName qName = QName.create("http://netconfcentral.org/ns/toaster", "make-toast"); 28 | 29 | public ToasterServiceMakeToastProcessor(final ToasterServiceImpl toasterService) { 30 | this.toasterService = toasterService; 31 | } 32 | 33 | @Override 34 | public QName getIdentifier() { 35 | return this.qName; 36 | } 37 | 38 | @Override 39 | public ListenableFuture> invoke(final MakeToastInput input) { 40 | LOG.info("execute RPC: make-toast"); 41 | return toasterService.makeToast(input); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/main/java/io/lighty/netconf/device/toaster/processors/ToasterServiceRestockToasterProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.toaster.processors; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import io.lighty.netconf.device.toaster.rpcs.ToasterServiceImpl; 12 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToaster; 13 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterInput; 14 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterOutput; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.opendaylight.yangtools.yang.common.RpcResult; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | @SuppressWarnings("checkstyle:MemberName") 21 | public class ToasterServiceRestockToasterProcessor extends ToasterServiceAbstractProcessor implements RestockToaster { 23 | 24 | private static final Logger LOG = LoggerFactory.getLogger(ToasterServiceRestockToasterProcessor.class); 25 | 26 | private final ToasterServiceImpl toasterService; 27 | private final QName qName = QName.create("http://netconfcentral.org/ns/toaster", "restock-toaster"); 28 | 29 | public ToasterServiceRestockToasterProcessor(final ToasterServiceImpl toasterService) { 30 | this.toasterService = toasterService; 31 | } 32 | 33 | @Override 34 | public QName getIdentifier() { 35 | return this.qName; 36 | } 37 | 38 | @Override 39 | public ListenableFuture> invoke(final RestockToasterInput input) { 40 | LOG.info("execute RPC: restock-toaster"); 41 | return toasterService.restockToaster(input); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/main/java/io/lighty/netconf/device/toaster/rpcs/ToasterServiceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.toaster.rpcs; 9 | 10 | import com.google.common.util.concurrent.ListenableFuture; 11 | import com.google.common.util.concurrent.SettableFuture; 12 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 13 | import io.lighty.netconf.device.requests.notification.NotificationPublishService; 14 | import java.util.concurrent.Callable; 15 | import java.util.concurrent.ExecutorService; 16 | import java.util.concurrent.Executors; 17 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToastInput; 18 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToastOutput; 19 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.CancelToastOutputBuilder; 20 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInput; 21 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastOutput; 22 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastOutputBuilder; 23 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterInput; 24 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterOutput; 25 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterOutputBuilder; 26 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterRestocked; 27 | import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterRestockedBuilder; 28 | import org.opendaylight.yangtools.yang.common.RpcResult; 29 | import org.opendaylight.yangtools.yang.common.RpcResultBuilder; 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | 33 | public class ToasterServiceImpl implements AutoCloseable { 34 | 35 | private static final Logger LOG = LoggerFactory.getLogger(ToasterServiceImpl.class); 36 | 37 | private final ExecutorService executor; 38 | private NotificationPublishService notificationPublishService; 39 | 40 | public ToasterServiceImpl() { 41 | this.executor = Executors.newFixedThreadPool(1); 42 | } 43 | 44 | @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") 45 | public ListenableFuture> makeToast(final MakeToastInput makeToastInput) { 46 | LOG.info("makeToast {} {}", makeToastInput.getToasterDoneness(), makeToastInput.getToasterToastType()); 47 | final SettableFuture> result = SettableFuture.create(); 48 | this.executor.submit(new Callable>() { 49 | @Override 50 | public RpcResult call() throws Exception { 51 | final MakeToastOutput output = new MakeToastOutputBuilder().build(); 52 | final RpcResult rpcResult = RpcResultBuilder.success(output).build(); 53 | result.set(rpcResult); 54 | return rpcResult; 55 | } 56 | }); 57 | return result; 58 | } 59 | 60 | @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") 61 | public ListenableFuture> cancelToast(final CancelToastInput input) { 62 | LOG.info("cancelToast"); 63 | final SettableFuture> result = SettableFuture.create(); 64 | this.executor.submit(new Callable>() { 65 | @Override 66 | public RpcResult call() throws Exception { 67 | final CancelToastOutput output = new CancelToastOutputBuilder().build(); 68 | final RpcResult rpcResult = RpcResultBuilder.success(output).build(); 69 | result.set(rpcResult); 70 | return rpcResult; 71 | } 72 | }); 73 | return result; 74 | } 75 | 76 | @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") 77 | public ListenableFuture> restockToaster(final RestockToasterInput input) { 78 | LOG.info("restockToaster {}", input.getAmountOfBreadToStock()); 79 | 80 | publishRestockNotification(input); 81 | 82 | final SettableFuture> result = SettableFuture.create(); 83 | 84 | this.executor.submit(new Callable>() { 85 | @Override 86 | public RpcResult call() throws Exception { 87 | final RestockToasterOutput output = new RestockToasterOutputBuilder().build(); 88 | final RpcResult rpcResult = RpcResultBuilder.success(output).build(); 89 | result.set(rpcResult); 90 | return rpcResult; 91 | } 92 | }); 93 | return result; 94 | } 95 | 96 | private void publishRestockNotification(RestockToasterInput input) { 97 | if (this.notificationPublishService != null) { 98 | ToasterRestocked reStockedNotification = new ToasterRestockedBuilder() 99 | .setAmountOfBread(input.getAmountOfBreadToStock()).build(); 100 | notificationPublishService.publish(reStockedNotification, ToasterRestocked.QNAME); 101 | } 102 | } 103 | 104 | public void setNotificationPublishService(NotificationPublishService notificationPublishService) { 105 | this.notificationPublishService = notificationPublishService; 106 | } 107 | 108 | @Override 109 | public void close() { 110 | this.executor.shutdown(); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/main/resources/initial-toaster-config-datastore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/main/resources/initial-toaster-operational-datastore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pantheon 5 | SuperToaster9000 6 | up 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/test/java/io/lighty/netconf/device/toaster/NotificationNetconfSessionListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.toaster; 9 | 10 | import java.util.concurrent.CountDownLatch; 11 | import org.opendaylight.netconf.api.messages.NetconfMessage; 12 | import org.opendaylight.netconf.client.NetconfClientSession; 13 | import org.opendaylight.netconf.client.SimpleNetconfClientSessionListener; 14 | 15 | public class NotificationNetconfSessionListener extends SimpleNetconfClientSessionListener { 16 | 17 | private CountDownLatch countDownLatch; 18 | private NetconfMessage receivedNotif; 19 | 20 | public NotificationNetconfSessionListener(CountDownLatch countDownLatch) { 21 | this.countDownLatch = countDownLatch; 22 | this.receivedNotif = null; 23 | } 24 | 25 | @Override 26 | public synchronized void onMessage(final NetconfClientSession session, final NetconfMessage message) { 27 | super.onMessage(session, message); 28 | if (isNotification(message)) { 29 | this.receivedNotif = message; 30 | this.countDownLatch.countDown(); 31 | } 32 | } 33 | 34 | public NetconfMessage getReceivedNotificationMessage() { 35 | return this.receivedNotif; 36 | } 37 | 38 | private boolean isNotification(NetconfMessage message) { 39 | return message.getDocument().getDocumentElement().getLocalName().equals("notification"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/test/resources/create_toaster_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 750 9 | Pantheon 10 | SuperToaster9000 11 | up 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/test/resources/get_schemas_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/test/resources/get_toaster_data_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/test/resources/make_toast_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | frozen-waffle 5 | 6 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/test/resources/restock_toast_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 4 | 5 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-device/src/test/resources/subscribe_to_notifications_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-multiple-devices/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | 15 | io.lighty.netconf.device.examples 16 | examples-parent 17 | 22.0.0-SNAPSHOT 18 | ../../parents/examples-parent/pom.xml 19 | 20 | 21 | lighty-toaster-multiple-devices 22 | jar 23 | 24 | 25 | io.lighty.netconf.device.toaster.Main 26 | true 27 | 28 | 29 | 30 | 31 | io.lighty.models.test 32 | lighty-toaster 33 | compile 34 | 35 | 36 | io.lighty.netconf.device.examples 37 | lighty-toaster-device 38 | 39 | 40 | org.junit.jupiter 41 | junit-jupiter-api 42 | test 43 | 44 | 45 | org.junit.jupiter 46 | junit-jupiter-engine 47 | test 48 | 49 | 50 | com.github.spotbugs 51 | spotbugs-annotations 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-multiple-devices/src/assembly/resources/start-device.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2021 PANTHEON.tech s.r.o. All rights reserved. 4 | # 5 | # This program and the accompanying materials are made available under the 6 | # terms of the Eclipse Public License v1.0 which accompanies this distribution, 7 | # and is available at http://www.eclipse.org/legal/epl-v10.html 8 | # 9 | # The script accepts parameters specifying the listening port, the number of devices and the number of threads for the NETCONF server. 10 | # Parameters are optional. If they are not used, the default value is used. 11 | # --device-count DEVICES-COUNT (Default 1) Number of simulated netconf devices to spin. This is the number of actual ports which will be used for the devices. 12 | # --starting-port STARTING-PORT (Default 17380) First port for simulated device. Each other device will use incremented port number. 13 | # --thread-pool-size THREAD-POOL-SIZE (Default 8) The number of threads to keep in the pool, when creating a device simulator, even if they are idle. 14 | # ./start-device --starting-port --device-count --thread-pool-size 15 | # ./start-device --starting-port 20000 --device-count 200 --thread-pool-size 200 16 | # 17 | 18 | CLASSPATH=lighty-toaster-multiple-devices-22.0.0-SNAPSHOT.jar 19 | 20 | ARGUMENT_LIST=( 21 | "device-count" 22 | "starting-port" 23 | "thread-pool-size" 24 | ) 25 | 26 | deviceCount=1 27 | startingPort=17830 28 | threadPoolSize=8 29 | 30 | # read arguments 31 | opts=$(getopt \ 32 | --longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")" \ 33 | --name "$(basename "$0")" \ 34 | --options "" \ 35 | -- "$@" 36 | ) 37 | 38 | eval set --$opts 39 | 40 | while [[ $# -gt 0 ]]; do 41 | case "$1" in 42 | --device-count) 43 | deviceCount=$2 44 | shift 2 45 | ;; 46 | 47 | --starting-port) 48 | startingPort=$2 49 | shift 2 50 | ;; 51 | 52 | --thread-pool-size) 53 | threadPoolSize=$2 54 | shift 2 55 | ;; 56 | 57 | *) 58 | break 59 | ;; 60 | esac 61 | done 62 | 63 | for jar in `ls -1 lib/`; 64 | do 65 | CLASSPATH=$CLASSPATH:lib/$jar 66 | done 67 | 68 | java -server -Xms16M -Xmx40M -XX:MaxMetaspaceSize=40m -classpath $CLASSPATH io.lighty.netconf.device.toaster.Main --starting-port $startingPort --thread-pool-size $threadPoolSize --device-count $deviceCount 69 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-multiple-devices/src/main/java/io/lighty/netconf/device/toaster/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.toaster; 9 | 10 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 11 | import io.lighty.core.common.models.ModuleId; 12 | import io.lighty.netconf.device.NetconfDevice; 13 | import io.lighty.netconf.device.NetconfDeviceBuilder; 14 | import io.lighty.netconf.device.toaster.processors.ToasterServiceCancelToastProcessor; 15 | import io.lighty.netconf.device.toaster.processors.ToasterServiceMakeToastProcessor; 16 | import io.lighty.netconf.device.toaster.rpcs.ToasterServiceImpl; 17 | import io.lighty.netconf.device.utils.ArgumentParser; 18 | import io.lighty.netconf.device.utils.ModelUtils; 19 | import java.io.File; 20 | import java.util.List; 21 | import java.util.Set; 22 | import net.sourceforge.argparse4j.inf.Namespace; 23 | import org.opendaylight.yangtools.binding.meta.YangModuleInfo; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | 28 | public final class Main { 29 | 30 | private static final Logger LOG = LoggerFactory.getLogger(Main.class); 31 | 32 | private ShutdownHook shutdownHook; 33 | 34 | public static void main(String[] args) { 35 | Main app = new Main(); 36 | app.start(args, true); 37 | } 38 | 39 | @SuppressFBWarnings({"SLF4J_SIGN_ONLY_FORMAT", "OBL_UNSATISFIED_OBLIGATION"}) 40 | public void start(String[] args, boolean registerShutdownHook) { 41 | //1. Load parameters 42 | final ArgumentParser argumentParser = new ArgumentParser(); 43 | final Namespace parseArguments = argumentParser.parseArguments(args); 44 | 45 | //parameters are stored as string list 46 | final List portList = parseArguments.get("port"); 47 | final int port = Integer.parseInt(String.valueOf(portList.getFirst())); 48 | 49 | LOG.info("Lighty-Toaster device started {}", port); 50 | LOG.info("___________ __ ________ .__"); 51 | LOG.info("\\__ ___/___ _______/ |_______\\______ \\ _______ _|__| ____ ____"); 52 | LOG.info(" | | / _ \\/ ___/\\ __\\_ __ \\ | \\_/ __ \\ \\/ / |/ ___\\/ __ \\"); 53 | LOG.info(" | |( <_> )___ \\ | | | | \\/ ` \\ ___/\\ /| \\ \\__\\ ___/"); 54 | LOG.info(" |____| \\____/____ > |__| |__| /_______ /\\___ >\\_/ |__|\\___ >___ >"); 55 | LOG.info(" \\/ \\/ \\/ \\/ \\/"); 56 | LOG.info("[https://lighty.io]"); 57 | 58 | //2. Load models from classpath 59 | Set toasterModules = ModelUtils.getModelsFromClasspath( 60 | ModuleId.from( 61 | "http://netconfcentral.org/ns/toaster", "toaster", "2009-11-20")); 62 | 63 | //3. Initialize DataStores 64 | File operationalFile = null; 65 | File configFile = null; 66 | final String configDir = System.getProperty("config.dir", 67 | "examples/devices/lighty-toaster-multiple-devices/src/main/resources"); 68 | if (argumentParser.isInitDatastore()) { 69 | LOG.info("Using initial datastore from: {}", configDir); 70 | operationalFile = new File( 71 | configDir, "initial-toaster-operational-datastore.xml"); 72 | configFile = new File( 73 | configDir, "initial-toaster-config-datastore.xml"); 74 | } 75 | if (argumentParser.isSaveDatastore()) { 76 | operationalFile = new File(configDir, "initial-toaster-operational-datastore.xml"); 77 | configFile = new File(configDir, "initial-toaster-config-datastore.xml"); 78 | } 79 | 80 | ToasterServiceImpl toasterService = new ToasterServiceImpl(); 81 | 82 | //parameters are stored as string list 83 | final List devicesList = parseArguments.get("port"); 84 | final int devicesCount = Integer.parseInt(String.valueOf(devicesList.getFirst())); 85 | final List threadList = parseArguments.get("port"); 86 | final int threadCount = Integer.parseInt(String.valueOf(threadList.getFirst())); 87 | 88 | //4. Initialize Netconf device 89 | NetconfDevice netconfDevice = new NetconfDeviceBuilder() 90 | .setCredentials("admin", "admin") 91 | .setBindingPort(port) 92 | .withModels(toasterModules) 93 | .withDefaultRequestProcessors() 94 | .withDefaultCapabilities() 95 | .withRequestProcessor(new ToasterServiceMakeToastProcessor(toasterService)) 96 | .withRequestProcessor(new ToasterServiceCancelToastProcessor(toasterService)) 97 | .setThreadPoolSize(threadCount) 98 | .setDeviceCount(devicesCount) 99 | .setOperationalDatastore(operationalFile) 100 | .setConfigDatastore(configFile) 101 | .build(); 102 | 103 | netconfDevice.start(); 104 | 105 | //5. Register shutdown hook 106 | this.shutdownHook = new ShutdownHook(netconfDevice,toasterService); 107 | if (registerShutdownHook) { 108 | Runtime.getRuntime().addShutdownHook(this.shutdownHook); 109 | } 110 | } 111 | 112 | public void shutdown() { 113 | if (shutdownHook != null) { 114 | shutdownHook.execute(); 115 | } 116 | } 117 | 118 | private static class ShutdownHook extends Thread { 119 | 120 | private final NetconfDevice netConfDevice; 121 | private final ToasterServiceImpl toasterService; 122 | 123 | ShutdownHook(NetconfDevice netConfDevice, ToasterServiceImpl toasterService) { 124 | this.netConfDevice = netConfDevice; 125 | this.toasterService = toasterService; 126 | } 127 | 128 | @Override 129 | public void run() { 130 | this.execute(); 131 | } 132 | 133 | @SuppressWarnings("checkstyle:IllegalCatch") 134 | public void execute() { 135 | LOG.info("Shutting down Lighty-Toaster device."); 136 | if (toasterService != null) { 137 | toasterService.close(); 138 | } 139 | if (netConfDevice != null) { 140 | try { 141 | netConfDevice.close(); 142 | } catch (Exception e) { 143 | LOG.error("Failed to close Netconf device properly", e); 144 | } 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-multiple-devices/src/main/resources/initial-toaster-config-datastore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-multiple-devices/src/main/resources/initial-toaster-operational-datastore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pantheon 5 | SuperToaster9000 6 | up 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-multiple-devices/src/test/resources/create_toaster_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 750 9 | Pantheon 10 | SuperToaster9000 11 | up 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-multiple-devices/src/test/resources/get_schemas_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-multiple-devices/src/test/resources/get_toaster_data_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/devices/lighty-toaster-multiple-devices/src/test/resources/make_toast_request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | frozen-waffle 5 | 6 | -------------------------------------------------------------------------------- /examples/devices/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | io.lighty.netconf.device.examples 15 | devices-aggregator 16 | 22.0.0-SNAPSHOT 17 | pom 18 | 19 | 20 | lighty-actions-device 21 | lighty-toaster-device 22 | lighty-network-topology-device 23 | lighty-toaster-multiple-devices 24 | lighty-notifications-device 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/models/lighty-example-data-center-model/README.md: -------------------------------------------------------------------------------- 1 | #lighty-example-data-center-model 2 | Contains example-data-center yang model. Model describes basic data center units like 3 | server and device. 4 | -------------------------------------------------------------------------------- /examples/models/lighty-example-data-center-model/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 4.0.0 11 | 12 | 13 | io.lighty.core 14 | lighty-binding-parent 15 | 21.1.0 16 | 17 | 18 | 19 | io.lighty.netconf.device.examples.models 20 | lighty-example-data-center-model 21 | 22.0.0-SNAPSHOT 22 | 23 | -------------------------------------------------------------------------------- /examples/models/lighty-example-data-center-model/src/main/yang/example-data-center@2018-08-07.yang: -------------------------------------------------------------------------------- 1 | module example-data-center { 2 | yang-version 1.1; 3 | namespace "urn:example:data-center"; 4 | prefix "sfarm"; 5 | revision 2018-08-07; 6 | 7 | list server { 8 | key name; 9 | leaf name { 10 | type string; 11 | } 12 | action reset { 13 | input { 14 | leaf reset-at { 15 | type string; 16 | mandatory true; 17 | } 18 | } 19 | output { 20 | leaf reset-finished-at { 21 | type string; 22 | mandatory true; 23 | } 24 | } 25 | } 26 | } 27 | 28 | container device { 29 | action start { 30 | input { 31 | leaf start-at { 32 | type string; 33 | mandatory true; 34 | } 35 | } 36 | output { 37 | leaf start-finished-at { 38 | type string; 39 | mandatory true; 40 | } 41 | } 42 | } 43 | } 44 | 45 | container box-out { 46 | container box-in { 47 | action open { 48 | } 49 | } 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /examples/models/lighty-example-network-topology-device-model/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 4.0.0 11 | 12 | 13 | io.lighty.core 14 | lighty-binding-parent 15 | 21.1.0 16 | 17 | 18 | 19 | io.lighty.netconf.device.examples.models 20 | lighty-example-network-topology-device-model 21 | 22.0.0-SNAPSHOT 22 | 23 | 24 | 25 | org.opendaylight.netconf 26 | netconf-client-mdsal 27 | 28 | 29 | org.opendaylight.netconf 30 | netconf-topology 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/models/lighty-example-notifications-model/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 4.0.0 11 | 12 | 13 | io.lighty.core 14 | lighty-binding-parent 15 | 21.1.0 16 | 17 | 18 | 19 | io.lighty.netconf.device.examples.models 20 | lighty-example-notifications-model 21 | 22.0.0-SNAPSHOT 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/models/lighty-example-notifications-model/src/main/yang/lighty-test-notifications@2018-08-20.yang: -------------------------------------------------------------------------------- 1 | module lighty-test-notifications { 2 | 3 | yang-version 1.1; 4 | 5 | namespace "yang:lighty:test:notifications"; 6 | prefix "ltn"; 7 | 8 | organization "Pantheon.tech"; 9 | 10 | description "This model is designed to test netconf notifications."; 11 | 12 | revision 2018-08-20 { 13 | description "Initial revision."; 14 | } 15 | 16 | rpc triggerDataNotification { 17 | description "Trigger dataNotification events."; 18 | input { 19 | leaf ClientId { 20 | type uint16; 21 | mandatory true; 22 | description "Id provided by client to identify origin of incoming notifications"; 23 | } 24 | leaf Count { 25 | type uint16; 26 | mandatory true; 27 | description "Number of notifications to be send by backend."; 28 | } 29 | leaf Delay { 30 | type uint32; 31 | mandatory true; 32 | description "Delay between notifications in milliseconds."; 33 | } 34 | leaf Payload { 35 | type string; 36 | mandatory true; 37 | description "Notification payload."; 38 | } 39 | } 40 | } 41 | 42 | notification dataNotification { 43 | leaf Ordinal { 44 | type uint16; 45 | mandatory true; 46 | description "Ordinal number of notification."; 47 | } 48 | leaf ClientId { 49 | type uint16; 50 | mandatory true; 51 | description "Id of client which triggered this notification"; 52 | } 53 | leaf Payload { 54 | type string; 55 | mandatory true; 56 | description "Notification payload."; 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /examples/models/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 4.0.0 11 | 12 | io.lighty.netconf.device.examples.models 13 | lighty-models-aggregator 14 | 22.0.0-SNAPSHOT 15 | pom 16 | 17 | 18 | lighty-example-data-center-model 19 | lighty-example-network-topology-device-model 20 | lighty-example-notifications-model 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/parents/examples-bom/README.md: -------------------------------------------------------------------------------- 1 | #bom module 2 | 3 | This parent contains dependencyManagement declarations of all published lighty components. 4 | -------------------------------------------------------------------------------- /examples/parents/examples-bom/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 4.0.0 11 | 12 | io.lighty.netconf.device.examples 13 | examples-bom 14 | 22.0.0-SNAPSHOT 15 | pom 16 | 17 | ${project.groupId}:${project.artifactId} 18 | 19 | This artifact contains dependencyManagement declarations of all published 20 | Lighty components. 21 | 22 | 23 | 24 | 25 | 26 | 27 | io.lighty.netconf.device.examples.models 28 | lighty-example-network-topology-device-model 29 | 22.0.0-SNAPSHOT 30 | 31 | 32 | io.lighty.netconf.device.examples.models 33 | lighty-example-data-center-model 34 | 22.0.0-SNAPSHOT 35 | 36 | 37 | io.lighty.netconf.device 38 | lighty-netconf-device 39 | 22.0.0-SNAPSHOT 40 | 41 | 42 | io.lighty.netconf.device.examples 43 | lighty-actions-device 44 | 22.0.0-SNAPSHOT 45 | 46 | 47 | io.lighty.netconf.device.examples 48 | lighty-toaster-device 49 | 22.0.0-SNAPSHOT 50 | 51 | 52 | io.lighty.netconf.device.examples 53 | lighty-network-topology-device 54 | 22.0.0-SNAPSHOT 55 | 56 | 57 | io.lighty.netconf.device.examples 58 | lighty-toaster-multiple-devices 59 | 22.0.0-SNAPSHOT 60 | 61 | 62 | io.lighty.netconf.device.examples.models 63 | lighty-example-notifications-model 64 | 22.0.0-SNAPSHOT 65 | 66 | 67 | 68 | org.junit.jupiter 69 | junit-jupiter-api 70 | 5.11.2 71 | 72 | 73 | org.junit.jupiter 74 | junit-jupiter-engine 75 | 5.11.2 76 | 77 | 78 | org.xmlunit 79 | xmlunit-core 80 | 2.10.0 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /examples/parents/examples-parent/README.md: -------------------------------------------------------------------------------- 1 | #examples-parent 2 | 3 | This module extends lighty-app-parent module from open source project 4 | [lighty-core](https://github.com/PANTHEONtech/lighty-core/blob/master/lighty-core/lighty-app-parent/pom.xml) 5 | by `lighty-netconf-simulator` specific versions used for example NETCONF devices. 6 | -------------------------------------------------------------------------------- /examples/parents/examples-parent/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | 15 | io.lighty.core 16 | lighty-app-parent 17 | 21.1.0 18 | 19 | 20 | 21 | io.lighty.netconf.device.examples 22 | examples-parent 23 | 22.0.0-SNAPSHOT 24 | pom 25 | 26 | ${project.groupId}:${project.artifactId} 27 | 28 | Parent pom for code artifacts using Lighty.io. 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-surefire-plugin 37 | 3.5.0 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | io.lighty.netconf.device.examples 47 | examples-bom 48 | 22.0.0-SNAPSHOT 49 | pom 50 | import 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /examples/parents/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 4.0.0 11 | 12 | io.lighty.netconf.device.examples.parents 13 | parents-aggregator 14 | pom 15 | 22.0.0-SNAPSHOT 16 | 17 | 18 | examples-parent 19 | examples-bom 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | io.lighty.netconf.device.examples 15 | examples-aggregator 16 | pom 17 | 22.0.0-SNAPSHOT 18 | 19 | 20 | parents 21 | models 22 | devices 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /lgtm.yml: -------------------------------------------------------------------------------- 1 | extraction: 2 | java: 3 | index: 4 | maven: 5 | settings_file: settings.xml 6 | -------------------------------------------------------------------------------- /lighty-netconf-device/README.md: -------------------------------------------------------------------------------- 1 | # NETCONF device 2 | This is NETCONF device base library enabling users to create own 3 | netconf device implementations. 4 | 5 | ## NETCONF commands 6 | ```ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null admin@127.0.0.1 -p 17830 -s netconf``` 7 | 8 | ``` 9 | 10 | 11 | urn:ietf:params:netconf:base:1.0 12 | 13 | 14 | ]]>]]> 15 | ``` 16 | ``` 17 | 19 | 20 | ]]>]]> 21 | ``` 22 | ``` 23 | 25 | 26 | ]]>]]> 27 | ``` 28 | 29 | 30 | 31 | ## Pyang 32 | In order to generate simple XML data skeleton from yang model use this pyang command: 33 | 34 | ```pyang -f sample-xml-skeleton YANG_FILE -o OUTPUT_FILE``` 35 | 36 | ## RPC edit-config 37 | Current implementation supports only simple requests. 38 | 39 | Current state supports: 40 | - default operations 41 | - only one operation per request 42 | - only one top level element (in config element) 43 | 44 | To be done: 45 | - operations are not fully compliant with RFC(all operations support, notifications defined inside tree, ...) 46 | - support multiple operations per request 47 | - support multiple top level elements (in config element) 48 | - refactor whole edit-config implementation 49 | - implement getting schema in different formats with get-schema RPC 50 | - configurable delay between request response - simulate device processing 51 | -------------------------------------------------------------------------------- /lighty-netconf-device/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | 15 | io.lighty.core 16 | lighty-parent 17 | 21.1.0 18 | 19 | 20 | 21 | io.lighty.netconf.device 22 | lighty-netconf-device 23 | 22.0.0-SNAPSHOT 24 | jar 25 | 26 | 27 | 28 | io.lighty.core 29 | lighty-common 30 | 31 | 32 | io.lighty.core 33 | lighty-codecs-util 34 | 35 | 36 | org.opendaylight.mdsal.binding.model.ietf 37 | rfc8639 38 | 39 | 40 | org.opendaylight.yangtools 41 | binding-data-codec-api 42 | 43 | 44 | org.opendaylight.netconf 45 | netconf-testtool 46 | 47 | 48 | ch.qos.logback 49 | logback-classic 50 | 51 | 52 | 53 | 54 | org.junit.jupiter 55 | junit-jupiter 56 | test 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/NetconfDevice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device; 9 | 10 | /** 11 | * This interface represents NETCONF device. 12 | */ 13 | public interface NetconfDevice extends AutoCloseable { 14 | 15 | /** 16 | * Starts NETCONF device. This action will start listening on TCP socket for incoming NETCONF traffic. 17 | */ 18 | void start(); 19 | 20 | /** 21 | * Provides configured services for this NETCONF device instance. 22 | */ 23 | NetconfDeviceServices getNetconfDeviceServices(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/NetconfDeviceServices.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device; 9 | 10 | import io.lighty.codecs.util.XmlNodeConverter; 11 | import io.lighty.netconf.device.requests.notification.NotificationPublishService; 12 | import org.opendaylight.mdsal.binding.api.DataBroker; 13 | import org.opendaylight.mdsal.binding.api.NotificationService; 14 | import org.opendaylight.mdsal.binding.dom.adapter.AdapterContext; 15 | import org.opendaylight.mdsal.dom.api.DOMDataBroker; 16 | import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference; 17 | 18 | /** 19 | * This API provides properly initialized services from NETCONF device instance. 20 | */ 21 | public interface NetconfDeviceServices { 22 | 23 | DataBroker getDataBroker(); 24 | 25 | DOMDataBroker getDOMDataBroker(); 26 | 27 | Inference getRootInference(); 28 | 29 | AdapterContext getAdapterContext(); 30 | 31 | NotificationService getNotificationService(); 32 | 33 | NotificationPublishService getNotificationPublishService(); 34 | 35 | XmlNodeConverter getXmlNodeConverter(); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/CommitRequestProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests; 9 | 10 | import io.lighty.netconf.device.response.Response; 11 | import io.lighty.netconf.device.response.ResponseData; 12 | import io.lighty.netconf.device.utils.RPCUtil; 13 | import java.util.Collections; 14 | import java.util.concurrent.CompletableFuture; 15 | import org.opendaylight.yangtools.yang.common.QName; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | import org.w3c.dom.Element; 19 | 20 | /** 21 | * Implementation of commit netconf protocol operation. 22 | */ 23 | public class CommitRequestProcessor extends OkOutputRequestProcessor { 24 | 25 | private static final Logger LOG = LoggerFactory.getLogger(CommitRequestProcessor.class); 26 | 27 | @Override 28 | protected CompletableFuture executeOkRequest(Element requestXmlElement) { 29 | LOG.info("commit: executeOkRequest"); 30 | final CompletableFuture responseFuture = new CompletableFuture<>(); 31 | responseFuture.complete(new ResponseData(Collections.emptyList())); 32 | return responseFuture; 33 | } 34 | 35 | @Override 36 | public QName getIdentifier() { 37 | return QName.create(RPCUtil.NETCONF_BASE_NAMESPACE, "commit"); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/DatastoreOutputRequestProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests; 9 | 10 | import com.google.common.util.concurrent.FluentFuture; 11 | import io.lighty.codecs.util.exception.SerializationException; 12 | import io.lighty.netconf.device.utils.RPCUtil; 13 | import io.lighty.netconf.device.utils.TimeoutUtil; 14 | import java.util.ArrayList; 15 | import java.util.Collections; 16 | import java.util.List; 17 | import java.util.Optional; 18 | import java.util.concurrent.ExecutionException; 19 | import java.util.concurrent.TimeUnit; 20 | import java.util.concurrent.TimeoutException; 21 | import javax.xml.parsers.DocumentBuilder; 22 | import javax.xml.parsers.ParserConfigurationException; 23 | import org.opendaylight.mdsal.common.api.LogicalDatastoreType; 24 | import org.opendaylight.mdsal.dom.api.DOMDataBroker; 25 | import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction; 26 | import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; 27 | import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; 28 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | import org.w3c.dom.Document; 32 | import org.w3c.dom.Element; 33 | import org.w3c.dom.Node; 34 | 35 | public abstract class DatastoreOutputRequestProcessor extends BaseRequestProcessor { 36 | 37 | private static final Logger LOG = LoggerFactory.getLogger(DatastoreOutputRequestProcessor.class); 38 | 39 | @Override 40 | protected String convertNormalizedNodeToXmlString(NormalizedNode normalizedNode) 41 | throws SerializationException { 42 | return getNetconfDeviceServices().getXmlNodeConverter() 43 | .serializeData(getNetconfDeviceServices().getRootInference(), normalizedNode).toString(); 44 | } 45 | 46 | protected List getAllDataFromDatastore(LogicalDatastoreType datastoreType) { 47 | DOMDataBroker domDataBroker = getNetconfDeviceServices().getDOMDataBroker(); 48 | Optional listData; 49 | try (DOMDataTreeReadTransaction domDataReadOnlyTransaction = domDataBroker.newReadOnlyTransaction()) { 50 | FluentFuture> readData = 51 | domDataReadOnlyTransaction.read(datastoreType, YangInstanceIdentifier.empty()); 52 | listData = readData.get(TimeoutUtil.TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 53 | 54 | if (listData.isPresent()) { 55 | ContainerNode containerNode = (ContainerNode) listData.get(); 56 | return new ArrayList<>(containerNode.body()); 57 | } 58 | } catch (ExecutionException | TimeoutException e) { 59 | LOG.error("Exception thrown while getting data from datastore!", e); 60 | } catch (InterruptedException e) { 61 | LOG.error("Interrupted while getting data from datastore!", e); 62 | Thread.currentThread().interrupt(); 63 | } 64 | return Collections.emptyList(); 65 | } 66 | 67 | @Override 68 | protected Document wrapToFinalDocumentReply(List responseOutput) 69 | throws ParserConfigurationException { 70 | // convert normalized nodes to xml nodes 71 | DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); 72 | Document newDocument = builder.newDocument(); 73 | List wrappedOutputNodes = new ArrayList<>(); 74 | if (!responseOutput.isEmpty()) { 75 | List outputNodes = convertOutputToXmlNodes(responseOutput, builder, newDocument); 76 | outputNodes.forEach(outputNode -> wrappedOutputNodes.add(newDocument.importNode(outputNode, true))); 77 | } 78 | 79 | // wrap nodes to final document 80 | newDocument.appendChild(wrapResponse(newDocument, wrappedOutputNodes)); 81 | String formattedResponse = RPCUtil.formatXml(newDocument.getDocumentElement()); 82 | LOG.debug("Response: {}.", formattedResponse); 83 | return newDocument; 84 | } 85 | 86 | private Node wrapResponse(Document document, List response) { 87 | Element rpcReply = document.createElementNS(RPCUtil.NETCONF_BASE_NAMESPACE, "rpc-reply"); 88 | Element data = document.createElementNS(RPCUtil.NETCONF_BASE_NAMESPACE, "data"); 89 | response.forEach(data::appendChild); 90 | rpcReply.appendChild(document.importNode(data, true)); 91 | return rpcReply; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/DeleteConfigRequestProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests; 9 | 10 | import io.lighty.netconf.device.response.Response; 11 | import io.lighty.netconf.device.utils.RPCUtil; 12 | import java.util.concurrent.CompletableFuture; 13 | import org.opendaylight.netconf.api.NetconfDocumentedException; 14 | import org.opendaylight.yangtools.yang.common.ErrorSeverity; 15 | import org.opendaylight.yangtools.yang.common.ErrorTag; 16 | import org.opendaylight.yangtools.yang.common.ErrorType; 17 | import org.opendaylight.yangtools.yang.common.QName; 18 | import org.w3c.dom.Element; 19 | 20 | public class DeleteConfigRequestProcessor extends OkOutputRequestProcessor { 21 | 22 | private static final String DELETE_CONFIG_RPC_NAME = "delete-config"; 23 | 24 | public DeleteConfigRequestProcessor() { 25 | } 26 | 27 | @Override 28 | public QName getIdentifier() { 29 | return QName.create(RPCUtil.NETCONF_BASE_NAMESPACE, DELETE_CONFIG_RPC_NAME); 30 | } 31 | 32 | @Override 33 | protected CompletableFuture executeOkRequest(Element requestXmlElement) { 34 | //Currently only running datastores are implemented, 35 | //in the future when other datastores are added, handling here needs to be done 36 | return CompletableFuture.failedFuture(new NetconfDocumentedException("operation-not-supported", 37 | ErrorType.RPC, 38 | ErrorTag.OPERATION_NOT_SUPPORTED, 39 | ErrorSeverity.ERROR)); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/GetConfigRequestProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests; 9 | 10 | import io.lighty.netconf.device.response.Response; 11 | import io.lighty.netconf.device.response.ResponseData; 12 | import io.lighty.netconf.device.utils.RPCUtil; 13 | import java.util.List; 14 | import java.util.concurrent.CompletableFuture; 15 | import org.opendaylight.mdsal.common.api.LogicalDatastoreType; 16 | import org.opendaylight.yangtools.yang.common.QName; 17 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 18 | import org.w3c.dom.Element; 19 | 20 | /** 21 | * Implementation of get-config netconf protocol operation. 22 | * https://tools.ietf.org/html/rfc6241#section-7 23 | */ 24 | public class GetConfigRequestProcessor extends DatastoreOutputRequestProcessor { 25 | 26 | private static final String GET_CONFIG_RPC_NAME = "get-config"; 27 | 28 | @Override 29 | public QName getIdentifier() { 30 | return QName.create(RPCUtil.NETCONF_BASE_NAMESPACE, GET_CONFIG_RPC_NAME); 31 | } 32 | 33 | @Override 34 | public CompletableFuture execute(Element requestXml) { 35 | final CompletableFuture responseFuture = new CompletableFuture<>(); 36 | final List allDataFromDatastore = 37 | getAllDataFromDatastore(LogicalDatastoreType.CONFIGURATION); 38 | responseFuture.complete(new ResponseData(allDataFromDatastore)); 39 | return responseFuture; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/GetRequestProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests; 9 | 10 | import io.lighty.netconf.device.response.Response; 11 | import io.lighty.netconf.device.response.ResponseData; 12 | import io.lighty.netconf.device.utils.RPCUtil; 13 | import java.util.List; 14 | import java.util.concurrent.CompletableFuture; 15 | import org.opendaylight.mdsal.common.api.LogicalDatastoreType; 16 | import org.opendaylight.yangtools.yang.common.QName; 17 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 18 | import org.w3c.dom.Element; 19 | 20 | /** 21 | * Implementation of get netconf protocol operation. 22 | * https://tools.ietf.org/html/rfc6241#section-7 23 | */ 24 | public class GetRequestProcessor extends DatastoreOutputRequestProcessor { 25 | 26 | private static final String GET_RPC_NAME = "get"; 27 | 28 | @Override 29 | public QName getIdentifier() { 30 | return QName.create(RPCUtil.NETCONF_BASE_NAMESPACE, GET_RPC_NAME); 31 | } 32 | 33 | @Override 34 | public CompletableFuture execute(Element requestXml) { 35 | final CompletableFuture responseFuture = new CompletableFuture<>(); 36 | final List allDataFromDatastore = 37 | getAllDataFromDatastore(LogicalDatastoreType.OPERATIONAL); 38 | responseFuture.complete(new ResponseData(allDataFromDatastore)); 39 | return responseFuture; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/OkOutputRequestProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests; 9 | 10 | import io.lighty.codecs.util.exception.SerializationException; 11 | import io.lighty.netconf.device.response.Response; 12 | import io.lighty.netconf.device.utils.RPCUtil; 13 | import java.util.ArrayList; 14 | import java.util.Collections; 15 | import java.util.List; 16 | import java.util.concurrent.CompletableFuture; 17 | import javax.xml.parsers.DocumentBuilder; 18 | import javax.xml.parsers.ParserConfigurationException; 19 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | import org.w3c.dom.Document; 23 | import org.w3c.dom.Element; 24 | import org.w3c.dom.Node; 25 | 26 | public abstract class OkOutputRequestProcessor extends BaseRequestProcessor { 27 | 28 | private static final Logger LOG = LoggerFactory.getLogger(OkOutputRequestProcessor.class); 29 | 30 | @Override 31 | protected final CompletableFuture execute(Element requestXmlElement) { 32 | return executeOkRequest(requestXmlElement); 33 | } 34 | 35 | protected abstract CompletableFuture executeOkRequest(Element requestXmlElement); 36 | 37 | @Override 38 | protected List convertOutputToXmlNodes(List responseOutput, DocumentBuilder builder, 39 | Document document) { 40 | return Collections.singletonList(RPCUtil.createOkNode(document)); 41 | } 42 | 43 | @Override 44 | protected String convertNormalizedNodeToXmlString(NormalizedNode normalizedNode) 45 | throws SerializationException { 46 | throw new IllegalStateException("This method should not be called!"); 47 | } 48 | 49 | @Override 50 | protected Document wrapToFinalDocumentReply(List responseOutput) 51 | throws ParserConfigurationException { 52 | // convert normalized nodes to xml nodes 53 | DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); 54 | Document newDocument = builder.newDocument(); 55 | List outputNodes = convertOutputToXmlNodes(responseOutput, builder, newDocument); 56 | // wrap nodes to final document 57 | List wrappedOutputNodes = new ArrayList<>(); 58 | outputNodes.forEach(outputNode -> wrappedOutputNodes.add(newDocument.importNode(outputNode, true))); 59 | newDocument.appendChild(wrapResponse(newDocument, wrappedOutputNodes)); 60 | String formattedResponse = RPCUtil.formatXml(newDocument.getDocumentElement()); 61 | LOG.debug("Response: {}.", formattedResponse); 62 | return newDocument; 63 | } 64 | 65 | private Node wrapResponse(Document document, List response) { 66 | Element rpcReply = document.createElementNS(RPCUtil.NETCONF_BASE_NAMESPACE, "rpc-reply"); 67 | response.forEach(rpcReply::appendChild); 68 | return rpcReply; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/RequestProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests; 9 | 10 | import io.lighty.netconf.device.NetconfDeviceServices; 11 | import org.opendaylight.yangtools.yang.common.QName; 12 | import org.w3c.dom.Document; 13 | import org.w3c.dom.Element; 14 | 15 | /** 16 | * Netconf request processor. 17 | * 18 | */ 19 | public interface RequestProcessor { 20 | 21 | /** 22 | * Returns the QName identifier of the implementation. 23 | * 24 | * @return FQN a FQN 25 | */ 26 | QName getIdentifier(); 27 | 28 | /** 29 | * Parses the input element and do its operation around it. 30 | * 31 | * @param requestXmlElement XML RPC request element 32 | * @return Document a document 33 | */ 34 | Document processRequest(Element requestXmlElement); 35 | 36 | /** 37 | * Inject services into this instance of request processor. 38 | * @param netconfDeviceServices NETCONF device services 39 | */ 40 | void init(NetconfDeviceServices netconfDeviceServices); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/RpcHandlerImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests; 9 | 10 | import io.lighty.netconf.device.NetconfDeviceServices; 11 | import io.lighty.netconf.device.utils.RPCUtil; 12 | import java.util.Map; 13 | import java.util.Optional; 14 | import org.opendaylight.netconf.api.xml.XmlElement; 15 | import org.opendaylight.netconf.test.tool.rpchandler.RpcHandler; 16 | import org.opendaylight.yangtools.yang.common.QName; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | import org.w3c.dom.Document; 20 | import org.w3c.dom.Element; 21 | 22 | public class RpcHandlerImpl implements RpcHandler { 23 | 24 | private static final Logger LOG = LoggerFactory.getLogger(RpcHandlerImpl.class); 25 | 26 | private final Map cache; 27 | 28 | public RpcHandlerImpl(final NetconfDeviceServices netconfDeviceServices, final Map cache) { 29 | this.cache = cache; 30 | this.cache.values().forEach(rp -> rp.init(netconfDeviceServices)); 31 | } 32 | 33 | @Override 34 | public Optional getResponse(final XmlElement rpcElement) { 35 | final Element element = rpcElement.getDomElement(); 36 | final String formattedRequest = RPCUtil.formatXml(element); 37 | LOG.debug("Received get request with payload:\n{} ", formattedRequest); 38 | final Optional processorForRequestOpt = getProcessorForRequest(element); 39 | if (processorForRequestOpt.isPresent()) { 40 | return Optional.ofNullable(processorForRequestOpt.get().processRequest(element)); 41 | } 42 | return Optional.empty(); 43 | } 44 | 45 | private Optional getProcessorForRequest(final Element element) { 46 | final String namespace = element.getNamespaceURI(); 47 | final String localName = element.getLocalName(); 48 | final RequestProcessor foundProcessor = this.cache.get(QName.create(namespace, localName)); 49 | return Optional.ofNullable(foundProcessor); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/RpcOutputRequestProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests; 9 | 10 | import io.lighty.codecs.util.ConverterUtils; 11 | import io.lighty.codecs.util.exception.SerializationException; 12 | import io.lighty.netconf.device.NetconfDeviceServices; 13 | import io.lighty.netconf.device.utils.RPCUtil; 14 | import java.util.ArrayList; 15 | import java.util.Collections; 16 | import java.util.List; 17 | import java.util.Optional; 18 | import javax.xml.parsers.DocumentBuilder; 19 | import javax.xml.parsers.ParserConfigurationException; 20 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 21 | import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; 22 | import org.opendaylight.yangtools.yang.model.api.RpcDefinition; 23 | import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | import org.w3c.dom.Document; 27 | import org.w3c.dom.Element; 28 | import org.w3c.dom.Node; 29 | import org.w3c.dom.NodeList; 30 | 31 | public abstract class RpcOutputRequestProcessor extends BaseRequestProcessor { 32 | 33 | private static final Logger LOG = LoggerFactory.getLogger(RpcOutputRequestProcessor.class); 34 | 35 | private RpcDefinition rpcDefinition; 36 | 37 | @Override 38 | public void init(NetconfDeviceServices netconfDeviceServices) { 39 | super.init(netconfDeviceServices); 40 | EffectiveModelContext schemaContext = getNetconfDeviceServices().getAdapterContext().currentSerializer() 41 | .getRuntimeContext().modelContext(); 42 | Optional rpcDefinitionOptional = 43 | ConverterUtils.loadRpc(schemaContext, getIdentifier()); 44 | if (rpcDefinitionOptional.isPresent()) { 45 | this.rpcDefinition = rpcDefinitionOptional.get(); 46 | } else { 47 | throw new IllegalStateException("RpcDefinition for " + getIdentifier() + " was not found!"); 48 | } 49 | } 50 | 51 | @Override 52 | protected String convertNormalizedNodeToXmlString(NormalizedNode normalizedNode) 53 | throws SerializationException { 54 | return getNetconfDeviceServices().getXmlNodeConverter() 55 | .serializeRpc(Absolute.of(rpcDefinition.getQName(), rpcDefinition.getOutput().getQName()), 56 | normalizedNode).toString(); 57 | } 58 | 59 | public RpcDefinition getRpcDefinition() { 60 | return rpcDefinition; 61 | } 62 | 63 | protected Absolute getRpcDefInputAbsolutePath() { 64 | return Absolute.of(rpcDefinition.getQName(), rpcDefinition.getInput().getQName()); 65 | } 66 | 67 | @Override 68 | protected Document wrapToFinalDocumentReply(List responseOutput) 69 | throws ParserConfigurationException { 70 | DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); 71 | Document newDocument = builder.newDocument(); 72 | if (!responseOutput.isEmpty()) { 73 | // convert normalized nodes to xml nodes 74 | List outputNodes = convertOutputToXmlNodes(responseOutput, builder, newDocument); 75 | List outputNodesData = new ArrayList<>(); 76 | NodeList nodeList = outputNodes.get(0).getChildNodes(); 77 | if (nodeList.getLength() < 1) { 78 | outputNodesData.add(RPCUtil.createOkNode(newDocument)); 79 | } else { 80 | for (int i = 0; i < nodeList.getLength(); i++) { 81 | Node node = nodeList.item(i); 82 | Element data = newDocument.createElementNS( 83 | getIdentifier().getNamespace().toString(), node.getNodeName()); 84 | final int length = node.getChildNodes().getLength(); 85 | for (int j = 0; j < length; j++) { 86 | data.appendChild(node.getFirstChild()); 87 | } 88 | outputNodesData.add(data); 89 | } 90 | } 91 | // wrap nodes to final document 92 | List wrappedOutputNodes = new ArrayList<>(); 93 | outputNodesData.forEach(outputNode -> wrappedOutputNodes.add(newDocument.importNode(outputNode, true))); 94 | newDocument.appendChild(wrapReplyResponse(newDocument, wrappedOutputNodes)); 95 | } else { 96 | // convert normalized nodes to xml nodes 97 | List outputNodes = Collections.singletonList(RPCUtil.createOkNode(newDocument)); 98 | List wrappedOutputNodes = new ArrayList<>(); 99 | outputNodes.forEach(outputNode -> wrappedOutputNodes.add(newDocument.importNode(outputNode, true))); 100 | newDocument.appendChild(wrapReplyResponse(newDocument, wrappedOutputNodes)); 101 | } 102 | String formattedResponse = RPCUtil.formatXml(newDocument.getDocumentElement()); 103 | LOG.debug("Response: {}.", formattedResponse); 104 | return newDocument; 105 | } 106 | 107 | private Node wrapReplyResponse(Document document, List response) { 108 | Element rpcReply = document.createElementNS(RPCUtil.NETCONF_BASE_NAMESPACE, "rpc-reply"); 109 | response.forEach(rpcReply::appendChild); 110 | return rpcReply; 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/notification/CreateSubscriptionRequestProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests.notification; 9 | 10 | import io.lighty.codecs.util.exception.SerializationException; 11 | import io.lighty.netconf.device.requests.BaseRequestProcessor; 12 | import io.lighty.netconf.device.response.Response; 13 | import io.lighty.netconf.device.response.ResponseData; 14 | import io.lighty.netconf.device.utils.RPCUtil; 15 | import java.util.ArrayList; 16 | import java.util.Collections; 17 | import java.util.List; 18 | import java.util.concurrent.CompletableFuture; 19 | import javax.xml.parsers.DocumentBuilder; 20 | import javax.xml.parsers.DocumentBuilderFactory; 21 | import javax.xml.parsers.ParserConfigurationException; 22 | import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput; 23 | import org.opendaylight.yangtools.yang.common.QName; 24 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | import org.w3c.dom.Document; 28 | import org.w3c.dom.Element; 29 | import org.w3c.dom.Node; 30 | 31 | 32 | public class CreateSubscriptionRequestProcessor extends BaseRequestProcessor { 33 | 34 | private static final String CREATE_SUBSCRIPTION_RPC_NAME = "create-subscription"; 35 | private static final Logger LOG = LoggerFactory.getLogger(CreateSubscriptionRequestProcessor.class); 36 | private String messageId; 37 | 38 | @Override 39 | public QName getIdentifier() { 40 | return QName.create(CreateSubscriptionInput.QNAME.getNamespace(), CREATE_SUBSCRIPTION_RPC_NAME); 41 | } 42 | 43 | @Override 44 | protected CompletableFuture execute(Element requestXmlElement) { 45 | messageId = requestXmlElement.getAttribute("message-id"); 46 | final CompletableFuture responseFuture = new CompletableFuture<>(); 47 | responseFuture.complete(new ResponseData(Collections.emptyList())); 48 | return responseFuture; 49 | } 50 | 51 | @SuppressWarnings("checkstyle:AvoidHidingCauseException") 52 | @Override 53 | protected Document wrapToFinalDocumentReply( 54 | List responseOutput) throws ParserConfigurationException { 55 | try { 56 | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 57 | factory.setNamespaceAware(true); 58 | DocumentBuilder builder = factory.newDocumentBuilder(); 59 | Document newDocument = builder.newDocument(); 60 | 61 | // convert normalized nodes to xml nodes 62 | List outputNodes = Collections.singletonList(RPCUtil.createOkNode(newDocument)); 63 | List wrappedOutputNodes = new ArrayList<>(); 64 | outputNodes.forEach(outputNode -> wrappedOutputNodes.add(newDocument.importNode(outputNode, true))); 65 | 66 | Element rpcReply = newDocument.createElementNS(RPCUtil.NETCONF_BASE_NAMESPACE, "rpc-reply"); 67 | rpcReply.setAttribute("message-id", messageId); 68 | wrappedOutputNodes.forEach(rpcReply::appendChild); 69 | newDocument.appendChild(rpcReply); 70 | 71 | String formattedResponse = RPCUtil.formatXml(newDocument.getDocumentElement()); 72 | LOG.debug("Response: {}.", formattedResponse); 73 | return newDocument; 74 | } catch (ParserConfigurationException e) { 75 | throw new RuntimeException("Error while creating create-subscription reply XML document"); 76 | } 77 | } 78 | 79 | @Override 80 | protected String convertNormalizedNodeToXmlString(NormalizedNode normalizedNode) 81 | throws SerializationException { 82 | throw new IllegalStateException("This method should not be called!"); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/notification/NotificationPublishService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests.notification; 9 | 10 | import org.opendaylight.yangtools.binding.Notification; 11 | import org.opendaylight.yangtools.yang.common.QName; 12 | 13 | /** 14 | * Service for publishing NETCONF notifications. 15 | * Schema context of NETCONF device must contain proper yang models 16 | * specified by RFC5277 17 | */ 18 | public interface NotificationPublishService { 19 | 20 | @SuppressWarnings({"checkstyle:NonEmptyAtClauseDescritption", "checkstyle:ParameterName"}) 21 | /** 22 | * Publish Notification. 23 | * @param notification 24 | * @param qName 25 | */ 26 | void publish(Notification notification, QName qName); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/notification/NotificationPublishServiceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests.notification; 9 | 10 | import java.util.Set; 11 | import org.opendaylight.mdsal.binding.dom.adapter.AdapterContext; 12 | import org.opendaylight.netconf.server.api.monitoring.Capability; 13 | import org.opendaylight.netconf.server.api.operations.NetconfOperationService; 14 | import org.opendaylight.netconf.test.tool.operations.OperationsCreator; 15 | import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType; 16 | import org.opendaylight.yangtools.binding.Notification; 17 | import org.opendaylight.yangtools.yang.common.QName; 18 | 19 | public class NotificationPublishServiceImpl implements OperationsCreator, NotificationPublishService { 20 | 21 | private NotificationOperation notificationOperation; 22 | private AdapterContext adapterContext; 23 | 24 | @Override 25 | public void publish(final Notification notification, final QName quName) { 26 | // If the device is not fully started, the mountPoint will not be available, so it is not able to 27 | // send the notification. 28 | if (this.notificationOperation != null) { 29 | this.notificationOperation.sendMessage(notification, quName); 30 | } 31 | } 32 | 33 | @Override 34 | public NetconfOperationService getNetconfOperationService(final Set capabilities, 35 | final SessionIdType idType) { 36 | this.notificationOperation = new NotificationOperation(this.adapterContext); 37 | return new NotificationService(this.notificationOperation, idType); 38 | } 39 | 40 | public void setAdapterContext(final AdapterContext adapterContext) { 41 | this.adapterContext = adapterContext; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/requests/notification/NotificationService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.requests.notification; 9 | 10 | import com.google.common.collect.Sets; 11 | import java.util.Optional; 12 | import java.util.Set; 13 | import org.opendaylight.netconf.server.api.operations.NetconfOperation; 14 | import org.opendaylight.netconf.server.api.operations.NetconfOperationService; 15 | import org.opendaylight.netconf.test.tool.rpc.DataList; 16 | import org.opendaylight.netconf.test.tool.rpc.SimulatedCommit; 17 | import org.opendaylight.netconf.test.tool.rpc.SimulatedCreateSubscription; 18 | import org.opendaylight.netconf.test.tool.rpc.SimulatedDiscardChanges; 19 | import org.opendaylight.netconf.test.tool.rpc.SimulatedEditConfig; 20 | import org.opendaylight.netconf.test.tool.rpc.SimulatedGet; 21 | import org.opendaylight.netconf.test.tool.rpc.SimulatedGetConfig; 22 | import org.opendaylight.netconf.test.tool.rpc.SimulatedLock; 23 | import org.opendaylight.netconf.test.tool.rpc.SimulatedUnLock; 24 | import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType; 25 | 26 | public class NotificationService implements NetconfOperationService { 27 | 28 | private final NetconfOperation netconfOperation; 29 | private final SessionIdType sessionIdType; 30 | 31 | NotificationService(final NetconfOperation netconfOperation, final SessionIdType idType) { 32 | this.netconfOperation = netconfOperation; 33 | this.sessionIdType = idType; 34 | } 35 | 36 | @Override 37 | public Set getNetconfOperations() { 38 | final DataList storage = new DataList(); 39 | final SimulatedGet sGet = new SimulatedGet(sessionIdType, storage); 40 | final SimulatedEditConfig sEditConfig = new SimulatedEditConfig(sessionIdType, storage); 41 | final SimulatedGetConfig sGetConfig = new SimulatedGetConfig(sessionIdType, storage, Optional.empty()); 42 | final SimulatedCommit sCommit = new SimulatedCommit(sessionIdType); 43 | final SimulatedLock sLock = new SimulatedLock(sessionIdType); 44 | final SimulatedUnLock sUnlock = new SimulatedUnLock(sessionIdType); 45 | final SimulatedCreateSubscription sCreateSubs = new SimulatedCreateSubscription(sessionIdType, 46 | Optional.empty()); 47 | final SimulatedDiscardChanges sDiscardChanges = new SimulatedDiscardChanges(sessionIdType); 48 | return Sets.newHashSet(sGet, sGetConfig, sEditConfig, sCommit, sLock, sUnlock, sCreateSubs, sDiscardChanges, 49 | netconfOperation); 50 | } 51 | 52 | @Override 53 | public void close() { 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/response/Response.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.response; 9 | 10 | import java.util.List; 11 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 12 | import org.w3c.dom.Document; 13 | 14 | public interface Response { 15 | 16 | /** 17 | * Data returned according to successful request. 18 | * 19 | * @return data 20 | */ 21 | List getData(); 22 | 23 | /** 24 | * Specific Error returned according to unsuccessful requests. 25 | * 26 | * @return error 27 | */ 28 | Document getErrorDocument(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/response/ResponseData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.response; 9 | 10 | import java.util.List; 11 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 12 | import org.w3c.dom.Document; 13 | 14 | public class ResponseData implements Response { 15 | 16 | private final List data; 17 | 18 | public ResponseData(final List data) { 19 | this.data = data; 20 | } 21 | 22 | @Override 23 | public List getData() { 24 | return data; 25 | } 26 | 27 | @Override 28 | public Document getErrorDocument() { 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/response/ResponseErrorMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.response; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | import org.opendaylight.netconf.api.NetconfDocumentedException; 13 | import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 14 | import org.w3c.dom.Document; 15 | 16 | public class ResponseErrorMessage implements Response { 17 | 18 | private final NetconfDocumentedException data; 19 | 20 | public ResponseErrorMessage(final NetconfDocumentedException data) { 21 | this.data = data; 22 | } 23 | 24 | @Override 25 | public List getData() { 26 | return Collections.emptyList(); 27 | } 28 | 29 | @Override 30 | public Document getErrorDocument() { 31 | return data.toXMLDocument(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/utils/ArgumentParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.utils; 9 | 10 | import com.google.common.base.Preconditions; 11 | import java.io.File; 12 | import java.util.List; 13 | import net.sourceforge.argparse4j.ArgumentParsers; 14 | import net.sourceforge.argparse4j.inf.Namespace; 15 | 16 | public class ArgumentParser { 17 | 18 | public static final int DEFAULT_PORT = 17830; 19 | public static final int DEFAULT_DEVICE_COUNT = 1; 20 | public static final int DEFAULT_POOL_SIZE = 8; 21 | 22 | private boolean initDatastore; 23 | private boolean saveDatastore; 24 | 25 | public Namespace parseArguments(final String[] args) { 26 | final net.sourceforge.argparse4j.inf.ArgumentParser argumentParser = 27 | ArgumentParsers.newFor("Lighty-netconf-simulator").build(); 28 | 29 | argumentParser.addArgument("-p", "--port") 30 | .nargs(1) 31 | .setDefault(List.of(DEFAULT_PORT)) 32 | .help("Sets port. If no value is set, default value is used (17830)."); 33 | argumentParser.addArgument("-i", "--init-datastore") 34 | .nargs(1) 35 | .help("Set path for the initial datastore folder which will be loaded. Folder must include two files " 36 | + "named initial-network-topo-config-datastore.xml and initial-network-topo-operational-datastore.xml"); 37 | argumentParser.addArgument("-o", "--output-datastore") 38 | .nargs(1) 39 | .help("Set path where the output datastore which will be saved."); 40 | argumentParser.addArgument("-d", "--devices-count") 41 | .setDefault(List.of(DEFAULT_DEVICE_COUNT)) 42 | .help("Number of simulated netconf devices to spin." 43 | + " This is the number of actual ports which will be used for the devices.") 44 | .dest("devices-count"); 45 | argumentParser.addArgument("-t", "--thread-pool-size") 46 | .setDefault(List.of(DEFAULT_POOL_SIZE)) 47 | .help("The number of threads to keep in the pool, " 48 | + "when creating a device simulator, even if they are idle.") 49 | .dest("thread-pool-size"); 50 | 51 | final Namespace namespace = argumentParser.parseArgsOrFail(args); 52 | if (!(namespace.getString("init_datastore") == null)) { 53 | initDatastore = true; 54 | final String pathDoesNotExist = "Input datastore %s does not exist"; 55 | final String filename = namespace.getString("init_datastore").replaceAll("[\\[\\]]", ""); 56 | final File file = new File(filename); 57 | Preconditions.checkArgument(file.exists(), String.format(pathDoesNotExist, filename)); 58 | } else { 59 | initDatastore = false; 60 | } 61 | saveDatastore = !(namespace.get("output_datastore") == null); 62 | 63 | return namespace; 64 | } 65 | 66 | public boolean isInitDatastore() { 67 | return initDatastore; 68 | } 69 | 70 | public boolean isSaveDatastore() { 71 | return saveDatastore; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/utils/DefaultOperation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.utils; 9 | 10 | import org.w3c.dom.Node; 11 | 12 | public enum DefaultOperation { 13 | NONE("none"), REPLACE("replace"), MERGE("merge"); 14 | private final String operationName; 15 | 16 | DefaultOperation(String name) { 17 | this.operationName = name; 18 | } 19 | 20 | public String getOperationName() { 21 | return operationName; 22 | } 23 | 24 | public static DefaultOperation getOperationByName(String operationName) { 25 | for (DefaultOperation operation : DefaultOperation.values()) { 26 | if (operation.getOperationName().equalsIgnoreCase(operationName)) { 27 | return operation; 28 | } 29 | } 30 | throw new UnsupportedOperationException( 31 | String.format("Default operation %s is not a valid name for netconf default operation", operationName)); 32 | } 33 | 34 | public static DefaultOperation getOperationByName(Node existingNode) { 35 | return getOperationByName(existingNode.getChildNodes().item(0).getTextContent()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/utils/ModelUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.utils; 9 | 10 | import com.google.common.collect.ImmutableSet; 11 | import io.lighty.core.common.models.ModuleId; 12 | import io.lighty.core.common.models.YangModuleUtils; 13 | import java.util.Arrays; 14 | import java.util.HashSet; 15 | import java.util.Set; 16 | import org.opendaylight.yangtools.binding.meta.YangModuleInfo; 17 | 18 | public final class ModelUtils { 19 | 20 | private ModelUtils() { 21 | throw new UnsupportedOperationException("do not instantiate utility class"); 22 | } 23 | 24 | public static final Set DEFAULT_CAPABILITIES = 25 | ImmutableSet.of("urn:ietf:params:netconf:base:1.0", "urn:ietf:params:netconf:base:1.1"); 26 | public static final String DEFAULT_NOTIFICATION_CAPABILITY = 27 | "urn:ietf:params:netconf:capability:notification:1.0"; 28 | 29 | /** 30 | * Get all Yang modules from classpath filtered by top-level module. 31 | * @param filter 32 | * The collection of top-level modules represented by name and revision. 33 | * @return 34 | * Collection top-level module and all of it's imported yang module dependencies recursively. 35 | * Empty collection is returned if no suitable modules are found. 36 | */ 37 | public static Set getModelsFromClasspath(final ModuleId... filter) { 38 | return YangModuleUtils.getModelsFromClasspath(new HashSet<>(Arrays.asList(filter))); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/utils/Operation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 PANTHEON.tech s.r.o. All Rights Reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v1.0 which accompanies this distribution, 6 | * and is available at https://www.eclipse.org/legal/epl-v10.html 7 | */ 8 | package io.lighty.netconf.device.utils; 9 | 10 | import org.w3c.dom.Node; 11 | 12 | public enum Operation { 13 | CREATE("create"), REPLACE("replace"), DELETE("delete"), REMOVE("remove"), MERGE("merge"); 14 | private final String operationName; 15 | 16 | Operation(String name) { 17 | this.operationName = name; 18 | } 19 | 20 | public String getOperationName() { 21 | return operationName; 22 | } 23 | 24 | public static Operation getOperationByName(String operationName) { 25 | for (Operation operation : Operation.values()) { 26 | if (operation.getOperationName().equalsIgnoreCase(operationName)) { 27 | return operation; 28 | } 29 | } 30 | throw new UnsupportedOperationException( 31 | String.format("Operation %s is not a valid name for netconf operation", operationName)); 32 | } 33 | 34 | public static Operation getOperationByName(Node existingNode) { 35 | Node namedItemNS = existingNode.getAttributes().getNamedItemNS(RPCUtil.NETCONF_BASE_NAMESPACE, "operation"); 36 | return getOperationByName(namedItemNS.getNodeValue()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/main/java/io/lighty/netconf/device/utils/TimeoutUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Pantheon Technologies s.r.o. All Rights Reserved. 3 | * 4 | * This Source Code Form is subject to the terms of the LIGHTY.IO LICENSE, 5 | * version 1.1. If a copy of the license was not distributed with this file, 6 | * You can obtain one at https://lighty.io/license/1.1/ 7 | */ 8 | 9 | package io.lighty.netconf.device.utils; 10 | 11 | public abstract class TimeoutUtil { 12 | 13 | public static final long TIMEOUT_MILLIS = 10_000; 14 | 15 | private TimeoutUtil() { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lighty-netconf-device/src/test/resources/initial-network-topo-config-datastore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | default-topology 5 | 6 | new-netconf-device-1 7 | 8 | 9 | new-netconf-device 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 4.0.0 13 | 14 | io.lighty.netconf.device 15 | netconf-device-aggregator 16 | 22.0.0-SNAPSHOT 17 | pom 18 | 19 | 20 | lighty-netconf-device 21 | examples 22 | 23 | 24 | --------------------------------------------------------------------------------