scrapli / scrapligo

scrapli, but in go!
MIT License
244 stars 35 forks source link

Cannot use SendCommand with too long commands on SR Linux #169

Closed vincentbernat closed 6 months ago

vincentbernat commented 6 months ago

Hey!

On SR Linux:

    driver.SendCommand("info from state system app-management application mgmt_server s")
    driver.SendCommand("info from state system app-management application mgmt_server st")
    driver.SendCommand("info from state system app-management application mgmt_server sta")
    driver.SendCommand("info from state system app-management application mgmt_server stat")
    driver.SendCommand("info from state system app-management application mgmt_server state")

I get:

    logging.go:54:     INFO SendCommand requested, sending 'info from state system app-management application mgmt_server s'
    logging.go:54:    DEBUG channel SendInput requested, sending input 'info from state system app-management application mgmt_server s'
    logging.go:54:    DEBUG channel write "info from state system app-management application mgmt_server s"
    logging.go:54:    DEBUG channel read "info from state system app-management application mgmt_server s"
    logging.go:54:    DEBUG channel write "\n"
    logging.go:54:    DEBUG channel read "\nParsing error: Unknown token 's'. Options are ['#', '>', '>>', 'author', 'cgroup', 'failure-action', 'failure-threshold', 'failure-window', 'last-change', 'last-start-type', 'launch-command', 'oom-score-adj', 'path', 'pid', 'restricted-operations', 'search-command', 'statistics', 'supported-restart-types', 'version', 'yang', '|']\n--{ [FACTORY] + running }--[  ]--\nA:e8a4de3b8e0a# "
    logging.go:54:     INFO SendCommand requested, sending 'info from state system app-management application mgmt_server st'
    logging.go:54:    DEBUG channel SendInput requested, sending input 'info from state system app-management application mgmt_server st'
    logging.go:54:    DEBUG channel write "info from state system app-management application mgmt_server st"
    logging.go:54:    DEBUG channel read "info from state system app-management application mgmt_server st "
    logging.go:54:    DEBUG channel write "\n"
    logging.go:54:    DEBUG channel read "t\nParsing error: Unknown token 'st'. Options are ['#', '>', '>>', 'author', 'cgroup', 'failure-action', 'failure-threshold', 'failure-window', 'last-change', 'last-start-type', 'launch-command', 'oom-score-adj', 'path', 'pid', 'restricted-operations', 'search-command', 'statistics', 'supported-restart-types', 'version', 'yang', '|']\n--{ [FACTORY] + running }--[  ]--\nA:e8a4de3b8e0a# "
    logging.go:54:     INFO SendCommand requested, sending 'info from state system app-management application mgmt_server sta'
    logging.go:54:    DEBUG channel SendInput requested, sending input 'info from state system app-management application mgmt_server sta'
    logging.go:54:    DEBUG channel write "info from state system app-management application mgmt_server sta"
    logging.go:54:    DEBUG channel read "info from state system app-management application mgmt_server staa"
    logging.go:54:    DEBUG channel write "\n"
    logging.go:54:    DEBUG channel read "\nParsing error: Unknown token 'sta'. Options are ['#', '>', '>>', 'author', 'cgroup', 'failure-action', 'failure-threshold', 'failure-window', 'last-change', 'last-start-type', 'launch-command', 'oom-score-adj', 'path', 'pid', 'restricted-operations', 'search-command', 'statistics', 'supported-restart-types', 'version', 'yang', '|']\n--{ [FACTORY] + running }--[  ]--\nA:e8a4de3b8e0a# "
    logging.go:54:     INFO SendCommand requested, sending 'info from state system app-management application mgmt_server stat'
    logging.go:54:    DEBUG channel SendInput requested, sending input 'info from state system app-management application mgmt_server stat'
    logging.go:54:    DEBUG channel write "info from state system app-management application mgmt_server stat"

And nothing else after that. The target is SR Linux 23.7.1 as a fresh Docker container.

hellt commented 6 months ago

Hi @vincentbernat can you show me how you set up the platform in your Go code?

vincentbernat commented 6 months ago
    t.Logf("SRLinux is listening at %s:%d", srLinuxHostname, srLinuxPort)
    logger, err := logging.NewInstance(
        logging.WithLogger(t.Log),
        logging.WithLevel(logging.Info),
    )
    if err != nil {
        t.Fatalf("NewInstance() error:\n%+v", err)
    }
    plat, err := platform.NewPlatform(
        "nokia_srl", srLinuxHostname,
        options.WithPort(srLinuxPort),
        options.WithAuthNoStrictKey(),
        options.WithAuthUsername("admin"),
        options.WithAuthPassword("NokiaSrl1!"),
        options.WithTransportType(transport.StandardTransport),
        options.WithLogger(logger),
    )
    if err != nil {
        t.Fatalf("NewPlatform() error:\n%+v", err)
    }
    driver, err := plat.GetNetworkDriver()
    if err != nil {
        t.Fatalf("GetNetworkDriver() error:\n%+v", err)
    }
    err = driver.Open()
    if err != nil {
        t.Fatalf("Open() error:\n%+v", err)
    }
    defer driver.Close()
hellt commented 6 months ago

It is expected to receive failures until you have a complete command. SR Linux by default has disabled complete-on-space, because we find it counter-productive for CLI users, given that autocompletion and suggestions are in place.

With this said, here is an example that works just fine:

package main

import (
    "fmt"

    "github.com/scrapli/scrapligo/driver/options"
    "github.com/scrapli/scrapligo/transport"

    "github.com/scrapli/scrapligo/platform"
)

func main() {
    p, err := platform.NewPlatform(
        // cisco_iosxe refers to the included cisco iosxe platform definition
        "nokia_srl",
        "clab-srl-srl",
        options.WithAuthNoStrictKey(),
        options.WithAuthUsername("admin"),
        options.WithAuthPassword("NokiaSrl1!"),
        options.WithTransportType(transport.StandardTransport),
    )
    if err != nil {
        fmt.Printf("failed to create platform; error: %+v\n", err)

        return
    }

    // fetch the network driver instance from the platform. you need to call this method explicitly
    // because the platform may be generic or network -- by having the explicit method to fetch the
    // driver you can avoid having to type cast things yourself. if you had a generic driver based
    // platform you could call `GetGenericDriver` instead.
    d, err := p.GetNetworkDriver()
    if err != nil {
        fmt.Printf("failed to fetch network driver from the platform; error: %+v\n", err)

        return
    }

    err = d.Open()
    if err != nil {
        fmt.Printf("failed to open driver; error: %+v\n", err)

        return
    }

    defer d.Close()

    // send a command -- as this is a driver created from a *platform* it will have some things
    // already done for us -- including disabling paging, so this command that would produce more
    // output than the default terminal lines will not cause any issues.
    r, err := d.SendCommand("info from state system app-management application mgmt_server state")
    if err != nil {
        fmt.Printf("failed to send command; error: %+v\n", err)
        return
    }
    if r.Failed != nil {
        fmt.Printf("response object indicates failure: %+v\n", r.Failed)

        return
    }

    fmt.Printf(
        "sent command '%s', output received (SendCommand):\n %s\n\n\n",
        r.Input,
        r.Result,
    )
}

Output:

go run private/main.go 
sent command 'info from state system app-management application mgmt_server state', output received (SendCommand):
     system {
        app-management {
            application mgmt_server {
                state running
            }
        }
    }
vincentbernat commented 6 months ago

I am a bit confused since I am now unable to reproduce the issue, but I have configured the container in the meantime. I have tried with a fresh container and I didn't run into the problem either. Note that my problem was not that the command was unsuccessful, it was just stuck. See the last line of log: there is a channel write and no channel read.

BTW, I thought that enter candidate and load factory auto-commit would restore the initial configuration, but this is not the case.

hellt commented 6 months ago

I see, tbh I don't use bare docker-based srl, always via containerlab, because there we init the system with some defaults enabling gnmi, etc.

Feel free to close this and reopen if/when the same issue occurs.