Started testing cobra based arg parser for cli_client

This commit is contained in:
mame82 2018-05-03 20:50:13 +00:00
parent 93e2d163ed
commit e2873af144
5 changed files with 178 additions and 1 deletions

27
USB_RPC.md Normal file
View File

@ -0,0 +1,27 @@
# USB gadget RPC mechanincs
- RPC server is in `service.go`
- RPC client with CLI is in `cli_client.go`
## RPC server
- holds state of desired USB setting with name `settingsState` and type `proto.GadgetSettings`
- `settingsState` is initialized to the hard-coded default settings when the RPC server is started (init) and deployed to the kernel via config FS
- the active USB gadget has not the same setting as the state stored in `settingsState`, this is only the case on init, when the default settings are deployed
- `settingsState` is meant to store the desired settings, which are customized by the user via RPC calls, in order to deploy the settings, an additional RPC call is needed (`deploySettings`)
- the user can change a single or multiple USB gadget settings with a single RPC call from the cli_client
- for this purpose, the RPC call `SetGadgetSettings` is used, which has to provide a full `proto.GadgetSettings` struct
- the settings provided with `SetGadgetSettings` overwrite the settings stored in `settingsState` (RPC doesn't keep track of changed and unchanged settings)
- thus, in order to change only a part of the settings, the client has to retrieve current `settingsState` via the RPC call `GetGadgetSettings` modify the result to its needs and send it back with `SetGadgetSettings`
- once the client is done with changing settings (could be done with a single or multiple calls to `SetGadgetSettings`) he issues the RPC call `deploySettings` to deploy the settings (real active seetings and `settingsState` are the same again, if no error occures)
- `GetDeployedGadgetSetting` RPC call could be used to retrieve the real settings in use from the running gadget
## Error handling
- the RPC server checks the settings to be valid after every call of `SetGadgetSettings`, if an error occures it is reported back and the `settingsState`isn't updated
- if `deploySettings` is called, the server stores the old settings of the gadgets, in case of an error it is reported back and the active gadget configuration, as well as the `settingsState`, are reverted to the stored configuration
- before Deploying new gadget settings, they are compared to the active ones, to avoid re-building of the composite gadget if it isn't needed
- the most likely reason to end up with invalid gadget settings is that too many USB gadgets functions are enabled simultaneously, as each function consumes one or more USB endpoints (there're only 7 EPs available)
## Additional notes
- the reason for not directly applying changed gadget settings, is that the whole composite gadget is destroyed and brought up again for every change
- there're likely parameters which could be changed without destroying the gadget (like the image backing an USB Mass Storage), these parameters are handled differently
- Re-deployment of the USB gagdget with changed settings interrupts the workflow, for example USB-based network interfaces are shut down during re-deployment (even if they aren't affected by the changed settings) - this would interrupt running connections or listening server sockets

View File

@ -8,7 +8,8 @@ import (
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "../proto"
pb "./proto"
"./cli_cmd"
"reflect"
)
@ -62,4 +63,6 @@ func main() {
log.Printf("Set LED to blink count 3")
c.SetLEDSettings(ctx, &pb.LEDSettings{ BlinkCount: 3})
*/
cli_cmd.Execute()
}

33
cli_cmd/led.go Normal file
View File

@ -0,0 +1,33 @@
package cli_cmd
import (
"fmt"
"github.com/spf13/cobra"
)
// usbCmd represents the usb command
var ledCmd = &cobra.Command{
Use: "led",
Short: "Set LED of P4wnP1",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("usb called")
},
}
func init() {
rootCmd.AddCommand(ledCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// usbCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// usbCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

73
cli_cmd/root.go Normal file
View File

@ -0,0 +1,73 @@
package cli_cmd
import (
"fmt"
"os"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "cli_client",
Short: "P4wnP1 (remote) CLI configuration",
Long: `The cli_client tool could be used to configure P4wnP1
from the command line. The tool relies on RPC so it could be used
remotely.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.test.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".test" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".test")
}
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}

41
cli_cmd/usb.go Normal file
View File

@ -0,0 +1,41 @@
package cli_cmd
import (
"fmt"
"github.com/spf13/cobra"
)
// usbCmd represents the usb command
var usbCmd = &cobra.Command{
Use: "usb",
Short: "Set or get USB Gadget settings",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("usb called")
},
}
var usbGetCmd = &cobra.Command{
Use: "get",
Short: "Get USB Gadget settings",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("usb get called %v", args)
},
}
func init() {
rootCmd.AddCommand(usbCmd)
usbCmd.AddCommand(usbGetCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// usbCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// usbCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}