freeconf / restconf

Implementation of RESTCONF Management protocol - IETF RFC8040
Apache License 2.0
29 stars 10 forks source link

Question: how to re-retrieve server configuration #62

Open b-kamphorst opened 4 months ago

b-kamphorst commented 4 months ago

Hi!

I'm still tweaking the "Next step" and "RESTCONF client" example. This time I want to start the car through the RPC and then see that status reflected in the car:running leaf:

import (
    "fmt"
    "strings"
    "testing"

    "github.com/freeconf/examples/car"
    "github.com/freeconf/restconf"
    "github.com/freeconf/restconf/client"
    "github.com/freeconf/restconf/device"
    "github.com/freeconf/yang/fc"
    "github.com/freeconf/yang/node"
    "github.com/freeconf/yang/nodeutil"
    "github.com/freeconf/yang/source"
)

func connectClient() {
    // YANG: just need YANG file ietf-yang-library.yang, not the yang of remote system as that will
    // be downloaded as needed
    ypath := restconf.InternalYPath

    // Connect
    proto := client.ProtocolHandler(ypath)
    dev, err := proto("http://localhost:9998/restconf")
    if err != nil {
        panic(err)
    }

    // Get a browser to walk server's management API for car
    car, err := dev.Browser("car")
    if err != nil {
        panic(err)
    }
    root := car.Root()
    defer root.Release()

        // Subscribe to notifications
        sel, err = root.Find("update")
    if err != nil {
        panic(err)
    }
    defer sel.Release()
    unsub, err := sel.Notifications(func(n node.Notification) {
        msg, err := nodeutil.WriteJSON(n.Event)
        if err != nil {
            panic(err)
        }
        fmt.Println(msg)
    })
    if err != nil {
        panic(err)
    }
    defer unsub()

    // Wait a bit just to ensure we receive the car started notification
    time.Sleep(time.Second)

    // Start car
    sel, err = root.Find("start")
    if err != nil {
        panic(err)
    }
    if _, err = sel.Action(nil); err != nil {
        panic(err)
    }

    println("Waiting for some notifications...")
    for i := 0; i < 10; i++ {
        sel, err = root.Find("running")
        if err != nil {
            panic(err)
        }
        running, err := sel.Get()
        if err != nil {
            panic(err)
        }
        fmt.Printf("Is the car running? %v\n", running)
        time.Sleep(time.Second)
    }
}

func main() {
    connectClient()
}

Output:

Waiting for some notifications...
Is the car running? false
{"event":"carStarted"}
Is the car running? false
Is the car running? false
Is the car running? false
Is the car running? false
Is the car running? false
{"event":"flatTire"}
{"event":"carStopped"}
Is the car running? false
Is the car running? false
Is the car running? false
Is the car running? false

I understand that the configuration is retrieved from the server and cached locally. I just wonder how I can forcibly re-retrieve the configuration? I appreciate your time!

dhubler commented 4 months ago

re:forcibly re-retrieve the config what do you mean? support for YANG PUSH spec?

re:other issue Sorry, haven't had the time to investigate the other issue yet, but hopefully soon.

On Mon, May 6, 2024 at 4:50 AM bart @.***> wrote:

Hi!

I'm still tweaking the "Next step" https://freeconf.org/docs/examples/next-step/ and "RESTCONF client" https://freeconf.org/docs/examples/restconf-client/ example. This time I want to start the car through the RPC and then see that status reflected in the car:running leaf:

import ( "fmt" "strings" "testing"

"github.com/freeconf/examples/car" "github.com/freeconf/restconf" "github.com/freeconf/restconf/client" "github.com/freeconf/restconf/device" "github.com/freeconf/yang/fc" "github.com/freeconf/yang/node" "github.com/freeconf/yang/nodeutil" "github.com/freeconf/yang/source" ) func connectClient() { // YANG: just need YANG file ietf-yang-library.yang, not the yang of remote system as that will // be downloaded as needed ypath := restconf.InternalYPath

// Connect proto := client.ProtocolHandler(ypath) dev, err := proto("http://localhost:9998/restconf") if err != nil { panic(err) }

// Get a browser to walk server's management API for car car, err := dev.Browser("car") if err != nil { panic(err) } root := car.Root() defer root.Release()

    // Subscribe to notifications
    sel, err = root.Find("update")

if err != nil { panic(err) } defer sel.Release() unsub, err := sel.Notifications(func(n node.Notification) { msg, err := nodeutil.WriteJSON(n.Event) if err != nil { panic(err) } fmt.Println(msg) }) if err != nil { panic(err) } defer unsub()

// Wait a bit just to ensure we receive the car started notification time.Sleep(time.Second)

// Start car sel, err = root.Find("start") if err != nil { panic(err) } if _, err = sel.Action(nil); err != nil { panic(err) }

println("Waiting for some notifications...") for i := 0; i < 10; i++ { sel, err = root.Find("running") if err != nil { panic(err) } running, err := sel.Get() if err != nil { panic(err) } fmt.Printf("Is the car running? %v\n", running) time.Sleep(time.Second) } } func main() { connectClient() }

Output:

Waiting for some notifications...Is the car running? false{"event":"carStarted"}Is the car running? falseIs the car running? falseIs the car running? falseIs the car running? falseIs the car running? false{"event":"flatTire"}{"event":"carStopped"}Is the car running? falseIs the car running? falseIs the car running? falseIs the car running? false

I understand that the configuration is retrieved from the server and cached locally. I just wonder how I can forcibly re-retrieve the configuration? I appreciate your time!

— Reply to this email directly, view it on GitHub https://github.com/freeconf/restconf/issues/62, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAACA7SPT4BQ2X7DB43267LZA473NAVCNFSM6AAAAABHIUIPZGVHI2DSMVQWIX3LMV43ASLTON2WKOZSGI4DAMZWHA2TEMQ . You are receiving this because you are subscribed to this thread.Message ID: @.***>

b-kamphorst commented 4 months ago

what do you mean? support for YANG PUSH spec?

Not per se, just requesting the current server config.

Sorry, haven't had the time to investigate the other issue yet, but hopefully soon.

No worries :) When it comes to open source projects, I'm happy to even get (swift) "have read" replies. I do want to use this on my work project though, so your help is much appreciated.

(NB I've started working on a PR for #60 to return the favour.)

b-kamphorst commented 4 months ago

It is quite crucial to us to be able to retrieve the latest server configuration (e.g. new GET request). From your previous remark I'm not sure if you understand the issue at hand and maybe we are just overlooking a function call. I'd be great if you can have a quick look to indicate whether this is (1) a misunderstanding on our side or (2) an issue in the framework.

b-kamphorst commented 4 months ago

Looking at https://pkg.go.dev/github.com/freeconf/yang/node#NewBrowser, which is called internally by dev, err := client.ProtocolHandler(ypath)(<url>), it seems to be by design and there is no easy way to get updated info other than create a new device object every time. Is that correct?

b-kamphorst commented 4 months ago

Seeing how Release was quite impactful in #61, I tried it here as well and it made quite a difference. Adding root.Release() as first line of the if-body produces expected output. Is this in line with what you would expect, and how you expect users to get updated info?