diff --git a/internal/app/ipc/networkmanager/com.openuc2.deviceadmin.networkmanager.varlink b/internal/app/ipc/networkmanager/com.openuc2.deviceadmin.networkmanager.varlink index 154dca6..f4b08d5 100644 --- a/internal/app/ipc/networkmanager/com.openuc2.deviceadmin.networkmanager.varlink +++ b/internal/app/ipc/networkmanager/com.openuc2.deviceadmin.networkmanager.varlink @@ -1,9 +1,15 @@ # com.openuc2.deviceadmin.networkmanager manages NetworkManager. interface com.openuc2.deviceadmin.networkmanager -# ReloadConnections reloads all network connection files from disk, including noticing any added or +# ReloadConnProfiles reloads all connection profiles from disk, including noticing any added or # deleted connection files. -method ReloadConnections() -> () +method ReloadConnProfiles() -> () + +# ReloadConnProfile reloads the UUID-specified connection profile from disk. +method ReloadConnProfile(uuid: string) -> () + +# The uuid input provided was invalid. +error InvalidUUID (description: string) # The service was unable to perform the requested operation for an unspecified reason. error Unknown (description: string) diff --git a/internal/app/ipc/networkmanager/comopenuc2deviceadminnetworkmanager.go b/internal/app/ipc/networkmanager/comopenuc2deviceadminnetworkmanager.go index c03f48a..6dcb058 100644 --- a/internal/app/ipc/networkmanager/comopenuc2deviceadminnetworkmanager.go +++ b/internal/app/ipc/networkmanager/comopenuc2deviceadminnetworkmanager.go @@ -12,6 +12,17 @@ import ( // Generated type declarations +// The uuid input provided was invalid. +type InvalidUUID struct { + Description string `json:"description"` +} + +func (e InvalidUUID) Error() string { + s := "com.openuc2.deviceadmin.networkmanager.InvalidUUID" + s += fmt.Sprintf("(Description: %v)", e.Description) + return s +} + // The service was unable to perform the requested operation for an unspecified reason. type Unknown struct { Description string `json:"description"` @@ -26,6 +37,17 @@ func (e Unknown) Error() string { func Dispatch_Error(err error) error { if e, ok := err.(*varlink.Error); ok { switch e.Name { + case "com.openuc2.deviceadmin.networkmanager.InvalidUUID": + errorRawParameters := e.Parameters.(*json.RawMessage) + if errorRawParameters == nil { + return e + } + var param InvalidUUID + err := json.Unmarshal(*errorRawParameters, ¶m) + if err != nil { + return e + } + return ¶m case "com.openuc2.deviceadmin.networkmanager.Unknown": errorRawParameters := e.Parameters.(*json.RawMessage) if errorRawParameters == nil { @@ -44,13 +66,13 @@ func Dispatch_Error(err error) error { // Generated client method calls -// ReloadConnections reloads all network connection files from disk, including noticing any added or +// ReloadConnProfiles reloads all connection profiles from disk, including noticing any added or // deleted connection files. -type ReloadConnections_methods struct{} +type ReloadConnProfiles_methods struct{} -func ReloadConnections() ReloadConnections_methods { return ReloadConnections_methods{} } +func ReloadConnProfiles() ReloadConnProfiles_methods { return ReloadConnProfiles_methods{} } -func (m ReloadConnections_methods) Call(ctx context.Context, c *varlink.Connection) (err_ error) { +func (m ReloadConnProfiles_methods) Call(ctx context.Context, c *varlink.Connection) (err_ error) { receive, err_ := m.Send(ctx, c, 0) if err_ != nil { return @@ -59,8 +81,8 @@ func (m ReloadConnections_methods) Call(ctx context.Context, c *varlink.Connecti return } -func (m ReloadConnections_methods) Send(ctx context.Context, c *varlink.Connection, flags uint64) (func(ctx context.Context) (uint64, error), error) { - receive, err := c.Send(ctx, "com.openuc2.deviceadmin.networkmanager.ReloadConnections", nil, flags) +func (m ReloadConnProfiles_methods) Send(ctx context.Context, c *varlink.Connection, flags uint64) (func(ctx context.Context) (uint64, error), error) { + receive, err := c.Send(ctx, "com.openuc2.deviceadmin.networkmanager.ReloadConnProfiles", nil, flags) if err != nil { return nil, err } @@ -74,8 +96,60 @@ func (m ReloadConnections_methods) Send(ctx context.Context, c *varlink.Connecti }, nil } -func (m ReloadConnections_methods) Upgrade(ctx context.Context, c *varlink.Connection) (func(ctx context.Context) (flags uint64, conn varlink.ReadWriterContext, err_ error), error) { - receive, err := c.Upgrade(ctx, "com.openuc2.deviceadmin.networkmanager.ReloadConnections", nil) +func (m ReloadConnProfiles_methods) Upgrade(ctx context.Context, c *varlink.Connection) (func(ctx context.Context) (flags uint64, conn varlink.ReadWriterContext, err_ error), error) { + receive, err := c.Upgrade(ctx, "com.openuc2.deviceadmin.networkmanager.ReloadConnProfiles", nil) + if err != nil { + return nil, err + } + return func(context.Context) (flags uint64, conn varlink.ReadWriterContext, err error) { + flags, conn, err = receive(ctx, nil) + if err != nil { + err = Dispatch_Error(err) + return + } + return + }, nil +} + +// ReloadConnProfile reloads the UUID-specified connection profile from disk. +type ReloadConnProfile_methods struct{} + +func ReloadConnProfile() ReloadConnProfile_methods { return ReloadConnProfile_methods{} } + +func (m ReloadConnProfile_methods) Call(ctx context.Context, c *varlink.Connection, uuid_in_ string) (err_ error) { + receive, err_ := m.Send(ctx, c, 0, uuid_in_) + if err_ != nil { + return + } + _, err_ = receive(ctx) + return +} + +func (m ReloadConnProfile_methods) Send(ctx context.Context, c *varlink.Connection, flags uint64, uuid_in_ string) (func(ctx context.Context) (uint64, error), error) { + var in struct { + Uuid string `json:"uuid"` + } + in.Uuid = uuid_in_ + receive, err := c.Send(ctx, "com.openuc2.deviceadmin.networkmanager.ReloadConnProfile", in, flags) + if err != nil { + return nil, err + } + return func(context.Context) (flags uint64, err error) { + flags, err = receive(ctx, nil) + if err != nil { + err = Dispatch_Error(err) + return + } + return + }, nil +} + +func (m ReloadConnProfile_methods) Upgrade(ctx context.Context, c *varlink.Connection, uuid_in_ string) (func(ctx context.Context) (flags uint64, conn varlink.ReadWriterContext, err_ error), error) { + var in struct { + Uuid string `json:"uuid"` + } + in.Uuid = uuid_in_ + receive, err := c.Upgrade(ctx, "com.openuc2.deviceadmin.networkmanager.ReloadConnProfile", in) if err != nil { return nil, err } @@ -92,7 +166,8 @@ func (m ReloadConnections_methods) Upgrade(ctx context.Context, c *varlink.Conne // Generated service interface with all methods type comopenuc2deviceadminnetworkmanagerInterface interface { - ReloadConnections(ctx context.Context, c VarlinkCall) error + ReloadConnProfiles(ctx context.Context, c VarlinkCall) error + ReloadConnProfile(ctx context.Context, c VarlinkCall, uuid_ string) error } // Generated service object with all methods @@ -101,6 +176,13 @@ type VarlinkCall struct{ varlink.Call } // Generated reply methods for all varlink errors +// The uuid input provided was invalid. +func (c *VarlinkCall) ReplyInvalidUUID(ctx context.Context, description_ string) error { + var out InvalidUUID + out.Description = description_ + return c.ReplyError(ctx, "com.openuc2.deviceadmin.networkmanager.InvalidUUID", &out) +} + // The service was unable to perform the requested operation for an unspecified reason. func (c *VarlinkCall) ReplyUnknown(ctx context.Context, description_ string) error { var out Unknown @@ -110,24 +192,43 @@ func (c *VarlinkCall) ReplyUnknown(ctx context.Context, description_ string) err // Generated reply methods for all varlink methods -func (c *VarlinkCall) ReplyReloadConnections(ctx context.Context) error { +func (c *VarlinkCall) ReplyReloadConnProfiles(ctx context.Context) error { + return c.Reply(ctx, nil) +} + +func (c *VarlinkCall) ReplyReloadConnProfile(ctx context.Context) error { return c.Reply(ctx, nil) } // Generated dummy implementations for all varlink methods -// ReloadConnections reloads all network connection files from disk, including noticing any added or +// ReloadConnProfiles reloads all connection profiles from disk, including noticing any added or // deleted connection files. -func (s *VarlinkInterface) ReloadConnections(ctx context.Context, c VarlinkCall) error { - return c.ReplyMethodNotImplemented(ctx, "com.openuc2.deviceadmin.networkmanager.ReloadConnections") +func (s *VarlinkInterface) ReloadConnProfiles(ctx context.Context, c VarlinkCall) error { + return c.ReplyMethodNotImplemented(ctx, "com.openuc2.deviceadmin.networkmanager.ReloadConnProfiles") +} + +// ReloadConnProfile reloads the UUID-specified connection profile from disk. +func (s *VarlinkInterface) ReloadConnProfile(ctx context.Context, c VarlinkCall, uuid_ string) error { + return c.ReplyMethodNotImplemented(ctx, "com.openuc2.deviceadmin.networkmanager.ReloadConnProfile") } // Generated method call dispatcher func (s *VarlinkInterface) VarlinkDispatch(ctx context.Context, call varlink.Call, methodname string) error { switch methodname { - case "ReloadConnections": - return s.comopenuc2deviceadminnetworkmanagerInterface.ReloadConnections(ctx, VarlinkCall{call}) + case "ReloadConnProfiles": + return s.comopenuc2deviceadminnetworkmanagerInterface.ReloadConnProfiles(ctx, VarlinkCall{call}) + + case "ReloadConnProfile": + var in struct { + Uuid string `json:"uuid"` + } + err := call.GetParameters(&in) + if err != nil { + return call.ReplyInvalidParameter(ctx, "parameters") + } + return s.comopenuc2deviceadminnetworkmanagerInterface.ReloadConnProfile(ctx, VarlinkCall{call}, in.Uuid) default: return call.ReplyMethodNotFound(ctx, methodname) @@ -146,9 +247,15 @@ func (s *VarlinkInterface) VarlinkGetDescription() string { return `# com.openuc2.deviceadmin.networkmanager manages NetworkManager. interface com.openuc2.deviceadmin.networkmanager -# ReloadConnections reloads all network connection files from disk, including noticing any added or +# ReloadConnProfiles reloads all connection profiles from disk, including noticing any added or # deleted connection files. -method ReloadConnections() -> () +method ReloadConnProfiles() -> () + +# ReloadConnProfile reloads the UUID-specified connection profile from disk. +method ReloadConnProfile(uuid: string) -> () + +# The uuid input provided was invalid. +error InvalidUUID (description: string) # The service was unable to perform the requested operation for an unspecified reason. error Unknown (description: string) diff --git a/internal/app/server/client/globals.go b/internal/app/server/client/globals.go index 3310002..510d9f9 100644 --- a/internal/app/server/client/globals.go +++ b/internal/app/server/client/globals.go @@ -11,7 +11,6 @@ import ( "github.com/openUC2/device-admin/internal/app/server/conf" "github.com/openUC2/device-admin/internal/clients/networkmanager" "github.com/openUC2/device-admin/internal/clients/sidecar" - "github.com/openUC2/device-admin/internal/clients/systemd" "github.com/openUC2/device-admin/internal/clients/tailscale" "github.com/openUC2/device-admin/internal/clients/templates" "github.com/openUC2/device-admin/internal/clients/udisks2" @@ -34,7 +33,6 @@ type Globals struct { Base *BaseGlobals Sidecar *sidecar.Client - Systemd *systemd.Client NetworkManager *networkmanager.Client Tailscale *tailscale.Client UDisks2 *udisks2.Client @@ -72,7 +70,6 @@ func NewGlobals(config conf.Config, l godest.Logger) (g *Globals, err error) { } g.Sidecar = sidecar.NewClient(config.Sidecar) - g.Systemd = systemd.NewClient(systemd.Config{}, g.Base.Logger) g.NetworkManager = networkmanager.NewClient(networkmanager.Config{}, g.Base.Logger) g.Tailscale = tailscale.NewClient(tailscale.Config{}, g.Base.Logger) g.UDisks2 = udisks2.NewClient(udisks2.Config{}, g.Base.Logger) diff --git a/internal/app/server/routes/boot/routes.go b/internal/app/server/routes/boot/routes.go index 10c8108..ece9999 100644 --- a/internal/app/server/routes/boot/routes.go +++ b/internal/app/server/routes/boot/routes.go @@ -14,22 +14,19 @@ import ( ipc "github.com/openUC2/device-admin/internal/app/ipc/boot" sh "github.com/openUC2/device-admin/internal/app/server/handling" sc "github.com/openUC2/device-admin/internal/clients/sidecar" - sd "github.com/openUC2/device-admin/internal/clients/systemd" ) type Handlers struct { r godest.TemplateRenderer - sdc *sd.Client scc *sc.Client l godest.Logger } -func New(r godest.TemplateRenderer, sdc *sd.Client, scc *sc.Client, l godest.Logger) *Handlers { +func New(r godest.TemplateRenderer, scc *sc.Client, l godest.Logger) *Handlers { return &Handlers{ r: r, - sdc: sdc, scc: scc, l: l, } @@ -69,7 +66,7 @@ func (h *Handlers) HandleBootPost() echo.HandlerFunc { // Run queries ctx := c.Request().Context() - if err := shutdown(ctx, state, h.scc, h.sdc, h.l); err != nil { + if err := shutdown(ctx, state, h.scc, h.l); err != nil { return err } // Redirect user @@ -91,7 +88,7 @@ func (h *Handlers) HandleBootPost() echo.HandlerFunc { } func shutdown( - ctx context.Context, state string, scc *sc.Client, sdc *sd.Client, l godest.Logger, + ctx context.Context, state string, scc *sc.Client, l godest.Logger, ) error { switch state { default: @@ -100,30 +97,15 @@ func shutdown( )) case "soft-rebooted": if err := shutdownViaSidecar(ctx, "SoftReboot", scc, l); err != nil { - if sdErr := sdc.SoftReboot(ctx); err != nil { - return errors.Wrapf( - sdErr, "couldn't soft-reboot through sidecar (%s) or directly", err.Error(), - ) - } - l.Warnf("soft-rebooted directly after failure to soft-reboot through sidecar", err) + return errors.Wrapf(err, "couldn't soft-reboot through sidecar") } case "rebooted": if err := shutdownViaSidecar(ctx, "Reboot", scc, l); err != nil { - if sdErr := sdc.Reboot(ctx); err != nil { - return errors.Wrapf( - sdErr, "couldn't reboot through sidecar (%s) or directly", err.Error(), - ) - } - l.Warnf("rebooted directly after failure to reboot through sidecar", err) + return errors.Wrapf(err, "couldn't reboot through sidecar") } case "powered-off": if err := shutdownViaSidecar(ctx, "Poweroff", scc, l); err != nil { - if sdErr := sdc.Poweroff(ctx); err != nil { - return errors.Wrapf( - sdErr, "couldn't power-off through sidecar (%s) or directly", err.Error(), - ) - } - l.Warnf("powered-off directly after failure to power-off through sidecar", err) + return errors.Wrapf(err, "couldn't power-off through sidecar") } } return nil diff --git a/internal/app/server/routes/internet/conn-profiles.go b/internal/app/server/routes/internet/conn-profiles.go index 163d151..c139a75 100644 --- a/internal/app/server/routes/internet/conn-profiles.go +++ b/internal/app/server/routes/internet/conn-profiles.go @@ -38,12 +38,7 @@ func (h *Handlers) HandleConnProfilesPost() echo.HandlerFunc { )) case "reloaded": if err := reloadConnProfilesViaSidecar(ctx, h.scc, h.l); err != nil { - if nmErr := h.nmc.ReloadConnProfiles(ctx); err != nil { - return errors.Wrapf( - nmErr, "couldn't reload through sidecar (%s) or directly", err.Error(), - ) - } - h.l.Warnf("reloaded directly after failure to reload through sidecar", err) + return errors.Wrapf(err, "couldn't reload through sidecar") } // Redirect user return c.Redirect(http.StatusSeeOther, redirectTarget) @@ -64,8 +59,8 @@ func reloadConnProfilesViaSidecar(ctx context.Context, scc *sc.Client, l godest. l.Error(errors.New("couldn't close connection to sidecar")) } }() - if err := ipc.ReloadConnections().Call(ctx, conn); err != nil { - return errors.Wrap(err, "couldn't call sidecar's ReloadConnections method") + if err := ipc.ReloadConnProfiles().Call(ctx, conn); err != nil { + return errors.Wrap(err, "couldn't call sidecar's ReloadConnProfiles method") } return nil } @@ -175,6 +170,12 @@ func (h *Handlers) HandleConnProfilePostByUUID() echo.HandlerFunc { if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("unparsable UUID %s", rawUUID)) } + + // Parse form + formValues, err := c.FormParams() + if err != nil { + return errors.Wrap(err, "couldn't load form parameters") + } state := c.FormValue("state") redirectTarget := c.FormValue("redirect-target") @@ -189,45 +190,55 @@ func (h *Handlers) HandleConnProfilePostByUUID() echo.HandlerFunc { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf( "invalid connection profiles state %s", state, )) + case "reloaded": + if err := reloadConnProfileViaSidecar(ctx, uid, h.scc, h.l); err != nil { + return errors.Wrapf(err, "couldn't reload connection profile %s", rawUUID) + } case "activated-transiently": if err := h.nmc.ActivateConnProfile(ctx, uid); err != nil { - return err + return errors.Wrapf(err, "couldn't activate connection profile %s", rawUUID) } - // Redirect user - return c.Redirect(http.StatusSeeOther, redirectTarget) case "simplified-updated", "simplified-updated-activated": - formValues, err := c.FormParams() - if err != nil { - return errors.Wrap(err, "couldn't load form parameters") - } - if err := updateConnProfile( - ctx, uid, "save and apply", formValues, h.nmc, - ); err != nil { + if err := updateConnProfile(ctx, uid, "save and apply", formValues, h.nmc); err != nil { return errors.Wrapf(err, "couldn't update connection profile %s", rawUUID) } if state == "simplified-updated-activated" { if err := h.nmc.ActivateConnProfile(ctx, uid); err != nil { - return err + return errors.Wrapf(err, "couldn't activate connection profile %s", rawUUID) } } - // Redirect user - return c.Redirect(http.StatusSeeOther, redirectTarget) case "updated": - formValues, err := c.FormParams() - if err != nil { - return errors.Wrap(err, "couldn't load form parameters") - } - if err := updateConnProfile( - ctx, uid, c.FormValue("update-type"), formValues, h.nmc, - ); err != nil { + updateType := c.FormValue("update-type") + if err := updateConnProfile(ctx, uid, updateType, formValues, h.nmc); err != nil { return errors.Wrapf(err, "couldn't update connection profile %s", rawUUID) } - // Redirect user - return c.Redirect(http.StatusSeeOther, redirectTarget) } + // Redirect user + return c.Redirect(http.StatusSeeOther, redirectTarget) } } +func reloadConnProfileViaSidecar( + ctx context.Context, uid uuid.UUID, scc *sc.Client, l godest.Logger, +) error { + conn, err := scc.Open(ctx) + if err != nil { + return errors.Wrap(err, "couldn't open connection to sidecar") + } + defer func() { + if conn == nil { + return + } + if err := conn.Close(); err != nil { + l.Error(errors.New("couldn't close connection to sidecar")) + } + }() + if err := ipc.ReloadConnProfile().Call(ctx, conn, uid.String()); err != nil { + return errors.Wrap(err, "couldn't call sidecar's ReloadConnProfiles method") + } + return nil +} + func updateConnProfile( ctx context.Context, uid uuid.UUID, updateType string, formValues url.Values, nmc *nm.Client, diff --git a/internal/app/server/routes/routes.go b/internal/app/server/routes/routes.go index 83a6ed2..da49730 100644 --- a/internal/app/server/routes/routes.go +++ b/internal/app/server/routes/routes.go @@ -43,7 +43,7 @@ func (h *Handlers) Register(er godest.EchoRouter, tsr turbostreams.Router, em go assets.RegisterStatic(h.r.BasePath, er, em) assets.NewTemplated(h.r).Register(er) - boot.New(h.r, h.globals.Systemd, h.globals.Sidecar, l).Register(er) + boot.New(h.r, h.globals.Sidecar, l).Register(er) cable.New( h.r, h.globals.Base.ACSigner, h.globals.Base.TSBroker, l, ).Register(er) diff --git a/internal/app/server/server.go b/internal/app/server/server.go index 9547848..4310e19 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -230,14 +230,6 @@ func (s *Server) runWorkersInContext(ctx context.Context) error { } return nil }) - eg.Go(func() error { - if err := s.Globals.Systemd.Open(ctx); err != nil { - s.Globals.Base.Logger.Error("couldn't open systemd client") - // Even if Systemd is unavailable, other parts of device-admin are still useful, so we - // don't propagate the error from here - } - return nil - }) eg.Go(func() error { if err := s.Globals.NetworkManager.Open(ctx); err != nil { s.Globals.Base.Logger.Error("couldn't open NetworkManager client") diff --git a/internal/app/sidecar/routes/networkmanager/routes.go b/internal/app/sidecar/routes/networkmanager/routes.go index 7b0dbc3..aa92272 100644 --- a/internal/app/sidecar/routes/networkmanager/routes.go +++ b/internal/app/sidecar/routes/networkmanager/routes.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/google/uuid" "github.com/pkg/errors" "github.com/sargassum-world/godest" "github.com/varlink/go/varlink" @@ -31,7 +32,7 @@ func (h *Handlers) Register(service *varlink.Service) error { return service.RegisterInterface(ipc.VarlinkNew(h)) } -func (h *Handlers) ReloadConnections(ctx context.Context, call ipc.VarlinkCall) error { +func (h *Handlers) ReloadConnProfiles(ctx context.Context, call ipc.VarlinkCall) error { if call.Request != nil { var req struct { Method string `json:"method"` @@ -50,5 +51,41 @@ func (h *Handlers) ReloadConnections(ctx context.Context, call ipc.VarlinkCall) } return err } - return call.ReplyReloadConnections(ctx) + return call.ReplyReloadConnProfiles(ctx) +} + +func (h *Handlers) ReloadConnProfile( + ctx context.Context, call ipc.VarlinkCall, rawUUID string, +) error { + if call.Request != nil { + var req struct { + Method string `json:"method"` + } + if err := json.Unmarshal(*call.Request, &req); err == nil { + h.l.Info(req.Method) + } + } + + uid, err := uuid.Parse(rawUUID) + if err != nil { + err = errors.Wrapf(err, "couldn't parse uuid %s", rawUUID) + if replyErr := call.ReplyError( + ctx, "com.openuc2.deviceadmin.networkmanager.InvalidUUID", + ipc.InvalidUUID{Description: err.Error()}, + ); replyErr != nil { + h.l.Error(err) + return errors.Wrapf(replyErr, "couldn't report error (%s) in method call reply", err.Error()) + } + return err + } + if err := h.nmc.ReloadConnProfile(ctx, uid); err != nil { + if replyErr := call.ReplyError( + ctx, "com.openuc2.deviceadmin.networkmanager.Unknown", ipc.Unknown{Description: err.Error()}, + ); replyErr != nil { + h.l.Error(err) + return errors.Wrapf(replyErr, "couldn't report error (%s) in method call reply", err.Error()) + } + return err + } + return call.ReplyReloadConnProfiles(ctx) } diff --git a/internal/clients/networkmanager/conn-profiles.go b/internal/clients/networkmanager/conn-profiles.go index f153cec..7ca8f6f 100644 --- a/internal/clients/networkmanager/conn-profiles.go +++ b/internal/clients/networkmanager/conn-profiles.go @@ -139,6 +139,36 @@ func (c *Client) ReloadConnProfiles(ctx context.Context) error { return nil } +func (c *Client) ReloadConnProfile(ctx context.Context, uid uuid.UUID) error { + conno, err := c.findConnProfileByUUID(ctx, uid) + if err != nil { + return errors.Wrapf(err, "couldn't find connection profile with uuid %s", uid) + } + + var filename string + const connName = nmName + ".Settings.Connection" + if err = conno.StoreProperty(connName+".Filename", &filename); err != nil { + return errors.Wrap(err, "couldn't query for filename") + } + if filename == "" { + return errors.Wrapf(err, "connection with uuid %s is not backed by a file!", uid) + } + + nm := c.getNetworkManagerSettings() + var status bool + var failures []string + if err = nm.CallWithContext( + ctx, nmName+".Settings.LoadConnections", 0, []string{filename}, + ).Store(&status, &failures); err != nil { + return errors.Wrap(err, "couldn't reload connection profiles") + } + if !status && len(failures) > 0 && len(failures[0]) > 0 { + return errors.Errorf("couldn't reload connection profile %s for uuid %s", filename, uid) + } + + return nil +} + func (c *Client) ActivateConnProfile(ctx context.Context, uid uuid.UUID) error { nm := c.getNetworkManager() conno, err := c.findConnProfileByUUID(ctx, uid) diff --git a/web/templates/internet/conn-profiles/index.page.tmpl b/web/templates/internet/conn-profiles/index.page.tmpl index 14d2f99..741ab5d 100644 --- a/web/templates/internet/conn-profiles/index.page.tmpl +++ b/web/templates/internet/conn-profiles/index.page.tmpl @@ -96,6 +96,31 @@ > + {{if ne .Data.ConnProfile.Filename ""}} +