lf-edge / eden

Eden is where EVE and Adam get tried and tested:
https://projecteve.dev
Apache License 2.0
49 stars 47 forks source link

[EPIC] Eden as library #828

Open uncleDecart opened 1 year ago

uncleDecart commented 1 year ago

What:

We want to refactor Eden so that we can use that as a standalone library, i.e. Right now you can do this

$ eden config add default
$ eden setup
$ eden start
$ eden eve onboard
$ eden pod deploy …

But after you’ll be able to do this as well

func setup() {
  eveCfg, _ := edenhelper.LoadConfig(utils.DefaultConfigPath())
  edenhelper.SetupEden(*eveCfg)
  edenhelper.StartEden(*eveCfg)
  edenhelper.OnboardEve(eveCfg.Eve.CertsUUID)
  evehelper.PodDeploy(*eveCfg, …)
}

Outcomes:

Related Issues

Roadmap

uncleDecart commented 1 year ago

@giggsoff @milan-zededa I propose use this space as discussion for further improvements and creating roadmap. I suggest we will close this EPIC once all of the issues on the roadmap will be merged. This list is to be increased. I'm copying Milan's comment on callback from #803 here:

I realize that I come a bit late for the review, but I was wondering if it would be possible to structure the openevec library in a more OOP way. Currently, it has a flat structure - consisting of a bunch of exported functions, most of which takes the big structure EdenSetupArgs. It is not very clear what each function actually uses from the structure and how it is related to other functions. Without a good knowledge of EVE (and Eden as implemented before) I would have hard time writing a program based on openevec. First, I would not know where to start.

The config structure is good as it is but I would prefer to work with handles, i.e. pointers to structures with the context, structured in a tree hierarchy for example. There could be a top-level handle for the library :

type OpenEVE struct {
    config *EdenSetupArgs
   // etc.
}

func Setup(Config *EdenSetupArgs) *OpenEVE

(what "c" actually stands for in openevec?)

From that I could ask for Adam() or Device(userFriendlyName) or SDN(), etc. (i.e. components of the framework) Device(userFriendlyName) would return a handle for the device:

type Device struct {
    userFriendlyName string
    uuid UUID
    config *EdenSetupArgs   // inherited from the parent OpenEVE
    // etc.
}

This handle could export methods like Config(), Status(), Start(), Stop(), Reboot(), Upgrade(), HardwareModel(), etc.. The config handle (returned by Device.Config()) would allow to retrieve handles for pods, volumes, networks and handles for these config items would allow to make modifications (create, modify, delete).

So the library would be used something like:


config := openevec.LoadConfig(path) // or something like that 
openEve := openevec.Setup(config)
device := openEve.Device() // since currently eden support only one EVE instance, the `userFriendlyName` arg could be left empty
config := device.Config()
volumes := config.Volumes()
for _, volume := range volumes {
    fmt.Println(volume)
}
volUUID := volumes.Add(eveapi.Volume{...})
//...
volumes.Delete(volUUID)
// ...
device.Reboot()
```golang

But that is just my proposal. Can be done later in a separate PR or rejected :)
uncleDecart commented 1 year ago

Copying my reply from #803 here

@milan-zededa regarding your comments

Most important one: "c" in openevec stands for controller :D

Your idea of handles could be very useful. But I think we can agree on one thing: we need to provide better API for eden as library. So far it is just 1:1 mapping of CLI commands to library functions. I.e. before you used

$ eden setup
$ eden start
$ eden eve onboard
$ eden pod deploy docker://nginx -p 8028:80 --mount=src=./data/helloeve,dst=/usr/share/nginx/html

Now you'll do this

viper_cfg, err := openevec.FromViper(*configName, *verbosity)
if err != nil {
  return err
}
openevec.SetupEden(viper_cfg)
openevec.Start(viper_cfg)
openevec.OnboardEve(viper_cfg.Eve.CertsUUID)
openevec.PodDeploy(viper_cfg)

It might not be perfect. But once it's in and we agree on API VERSIONING we will be able to experiment however we wan, without creating bomb commits and going through all of the code base. My idea was really to build on top of eden, something like UNIX philosophy. Meaning eden stays as set of functions with deep interface which just works. So my vision is that eden is set of functions that can help to deploy something on eve. Rest should be hidden! (Yes, that creates big discussion about tons of parameters we have, which we can tinker) How I see us going there: right now we have this bulky functions with too large cfg object and that makes it a little uncomfortable (as it should actually). Next step will be to purge config file from thing called runtime and put all of the parameters outside functions. That will make them bloated and we will have question wether or not we need all of this parameters and functions in the way they are right now. That way we will clean up functions and can have more insight on what we actually need. With fixed API we can create something of an environment provider. Where you have contexts on where are you right now and what you are doing. This context can be used in test framework to replace e-script. Such modularity will have precise goals: in eden we are answering the question: what is really should be in interface to make EVE running. In environment provider we answering question: using eden api, how can we create environments required and in testing we answer question for given environment setup, what should work.