@@ -24,18 +24,18 @@ const RumprunUnikernel string = "rumprun"
2424const SubnetMask125 = "128.0.0.0"
2525
2626type Rumprun struct {
27- Command string `json:"cmdline"`
28- Net RumprunNet `json:"net"`
29- Blk RumprunBlk `json:"blk"`
27+ Command string
28+ Envs []string
29+ Net RumprunNet
30+ Blk RumprunBlk
3031}
3132
32- type RumprunNoNet struct {
33- Command string `json:"cmdline"`
34- Blk RumprunBlk `json:"blk"`
33+ type RumprunCmd struct {
34+ CmdLine string `json:"cmdline"`
3535}
3636
37- type RumprunCmd struct {
38- Cmdline string `json:"cmdline "`
37+ type RumprunEnv struct {
38+ Env string `json:"env "`
3939}
4040
4141type RumprunNet struct {
@@ -56,25 +56,69 @@ type RumprunBlk struct {
5656}
5757
5858func (r * Rumprun ) CommandString () (string , error ) {
59- // if EthDeviceMask is empty, there is no network support. omit every relevant field
60- if r .Net .Mask == "" {
61- tmp := RumprunNoNet {
62- Command : r .Command ,
63- Blk : r .Blk ,
59+ // Rumprun accepts a JSON string to configure the unikernel. However,
60+ // Rumprun does not use a valid JSON format. Therefore, we manually
61+ // construct the JSON instead of using Go's json Marshal.
62+ // For more information check https://github.com/rumpkernel/rumprun/blob/master/doc/config.md
63+ cmdJSONString := ""
64+ envJSONString := ""
65+ netJSONString := ""
66+ blkJSONString := ""
67+ cmd := RumprunCmd {
68+ CmdLine : r .Command ,
69+ }
70+ cmdJSON , err := json .Marshal (cmd )
71+ if err != nil {
72+ return "" , fmt .Errorf ("Could not Marshal cmdline: %v" , err )
73+ }
74+ cmdJSONString = string (cmdJSON )
75+ for i , eVar := range r .Envs {
76+ eVar := RumprunEnv {
77+ Env : eVar ,
6478 }
65- jsonData , err := json .Marshal (tmp )
79+ oneVarJSON , err := json .Marshal (eVar )
80+ if err != nil {
81+ return "" , fmt .Errorf ("Could not Marshal environment variable: %v" , err )
82+ }
83+ if i != 0 {
84+ envJSONString += ","
85+ }
86+ oneVarJSONString := string (oneVarJSON )
87+ oneVarJSONString = strings .TrimPrefix (oneVarJSONString , "{" )
88+ oneVarJSONString = strings .TrimSuffix (oneVarJSONString , "}" )
89+ envJSONString += oneVarJSONString
90+ }
91+ // if Address is empty, we will spawn the unikernel without networking
92+ if r .Net .Address != "" {
93+ netJSON , err := json .Marshal (r .Net )
6694 if err != nil {
6795 return "" , err
6896 }
69- jsonStr := string ( jsonData )
70- return jsonStr , nil
97+ netJSONString = " \" net \" :"
98+ netJSONString += string ( netJSON )
7199 }
72- jsonData , err := json .Marshal (r )
73- if err != nil {
74- return "" , err
100+ // if Source is empty, we will spawn the unikernel without a block device
101+ if r .Blk .Source != "" {
102+ blkJSON , err := json .Marshal (r .Blk )
103+ if err != nil {
104+ return "" , err
105+ }
106+ blkJSONString = "\" blk\" :"
107+ blkJSONString += string (blkJSON )
75108 }
76- jsonStr := string (jsonData )
77- return jsonStr , nil
109+ finalJSONString := strings .TrimSuffix (cmdJSONString , "}" )
110+ if envJSONString != "" {
111+ finalJSONString += "," + envJSONString
112+ }
113+ if netJSONString != "" {
114+ finalJSONString += "," + netJSONString
115+ }
116+ if blkJSONString != "" {
117+ finalJSONString += "," + blkJSONString
118+ }
119+ finalJSONString += "}"
120+ fmt .Println (finalJSONString )
121+ return finalJSONString , nil
78122}
79123
80124func (r * Rumprun ) SupportsBlock () bool {
@@ -117,9 +161,13 @@ func (r *Rumprun) MonitorCli(_ string) string {
117161func (r * Rumprun ) Init (data UnikernelParams ) error {
118162 // if EthDeviceMask is empty, there is no network support
119163 if data .EthDeviceMask != "" {
120- // FIXME: in the case of rumprun & k8s, we need to explicitly set the mask
121- // to an inclusive value (eg 1 or 0), as NetBSD complains and does not set the default gw
122- // if it is not reachable from the IP address directly.
164+ // FIXME: in the case of rumprun & k8s, we need to identofy
165+ // the reason that networking is not working properly.
166+ // One reason could be that the gw is in different subnet
167+ // than the IP of the unikernel.
168+ // For that reason, we might need to set the mask to an
169+ // inclusive value (e.g. 0 or 1).
170+ // However, further exploration of this issue is necessary.
123171 mask , err := subnetMaskToCIDR (SubnetMask125 )
124172 if err != nil {
125173 return err
@@ -131,14 +179,25 @@ func (r *Rumprun) Init(data UnikernelParams) error {
131179 r .Net .Address = data .EthDeviceIP
132180 r .Net .Mask = fmt .Sprintf ("%d" , mask )
133181 r .Net .Gateway = data .EthDeviceGateway
182+ } else {
183+ // Set address to empty string so we can know that no network
184+ // was specified.
185+ r .Net .Address = ""
134186 }
135187
136- r .Blk .Source = "etfs"
137- r .Blk .Path = "/dev/ld0a"
138- r .Blk .FsType = "blk"
139- r .Blk .Mountpoint = "/data"
188+ if data .BlockMntPoint != "" {
189+ r .Blk .Source = "etfs"
190+ r .Blk .Path = "/dev/ld0a"
191+ r .Blk .FsType = "blk"
192+ r .Blk .Mountpoint = data .BlockMntPoint
193+ } else {
194+ // Set source to empty string so we can know that no block
195+ // was specified.
196+ r .Blk .Source = ""
197+ }
140198
141199 r .Command = strings .Join (data .CmdLine , " " )
200+ r .Envs = data .EnvVars
142201
143202 return nil
144203}
0 commit comments