diff --git a/docs/user_guide/api/targets.md b/docs/user_guide/api/targets.md index 5b0ee23b..47d5c687 100644 --- a/docs/user_guide/api/targets.md +++ b/docs/user_guide/api/targets.md @@ -193,4 +193,42 @@ Returns an empty body if successful. "Error Text" ] } - ``` \ No newline at end of file + ``` + +## `PATCH /api/v1/targets/{id}/subscriptions` + +Updates existing subscriptions for the target ID + +Returns an empty body if successful. + +=== "Request" + ```bash + curl --request PATCH gnmic-api-address:port/api/v1/targets/192.168.1.131:57400/subscriptions -d '{"subscriptions": ["sub1", "sub2"]}' + ``` +=== "200 OK" + ```json + ``` +=== "404 Not found" + ```json + { + "errors": [ + "target $target not found" + ] + } + ``` +=== "400 Bad Request" + ```json + { + "errors": [ + "subscription $subscription does not exist" + ] + } + ``` +=== "500 Internal Server Error" + ```json + { + "errors": [ + "Error Text" + ] + } + ``` diff --git a/pkg/app/api.go b/pkg/app/api.go index 49c77c3c..3a2ca7e0 100644 --- a/pkg/app/api.go +++ b/pkg/app/api.go @@ -113,6 +113,43 @@ func (a *App) handleConfigTargetsPost(w http.ResponseWriter, r *http.Request) { a.AddTargetConfig(tc) } +func (a *App) handleConfigTargetsSubscriptions(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["id"] + if !a.targetConfigExists(id) { + w.WriteHeader(http.StatusNotFound) + json.NewEncoder(w).Encode(APIErrors{Errors: []string{fmt.Sprintf("target %q not found", id)}}) + return + } + body, err := io.ReadAll(r.Body) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(APIErrors{Errors: []string{err.Error()}}) + return + } + defer r.Body.Close() + + var data map[string][]string + err = json.Unmarshal(body, &data) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(APIErrors{Errors: []string{err.Error()}}) + return + } + subs, ok := data["subscriptions"] + if !ok { + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(APIErrors{Errors: []string{"subscriptions not found"}}) + return + } + err = a.UpdateTargetSubscription(a.ctx, id, subs) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(APIErrors{Errors: []string{err.Error()}}) + return + } +} + func (a *App) handleConfigTargetsDelete(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] diff --git a/pkg/app/routes.go b/pkg/app/routes.go index 77128be0..52d4a2cc 100644 --- a/pkg/app/routes.go +++ b/pkg/app/routes.go @@ -36,6 +36,7 @@ func (a *App) configRoutes(r *mux.Router) { r.HandleFunc("/config/targets/{id}", a.handleConfigTargetsGet).Methods(http.MethodGet) r.HandleFunc("/config/targets", a.handleConfigTargetsPost).Methods(http.MethodPost) r.HandleFunc("/config/targets/{id}", a.handleConfigTargetsDelete).Methods(http.MethodDelete) + r.HandleFunc("/config/targets/{id}/subscriptions", a.handleConfigTargetsSubscriptions).Methods(http.MethodPatch) // config/subscriptions r.HandleFunc("/config/subscriptions", a.handleConfigSubscriptions).Methods(http.MethodGet) // config/outputs diff --git a/pkg/app/target.go b/pkg/app/target.go index 904c2cd9..69b02a55 100644 --- a/pkg/app/target.go +++ b/pkg/app/target.go @@ -43,7 +43,6 @@ func (a *App) initTarget(tc *types.TargetConfig) (*target.Target, error) { return t, nil } return t, nil - } func (a *App) stopTarget(ctx context.Context, name string) error { @@ -96,6 +95,27 @@ func (a *App) DeleteTarget(ctx context.Context, name string) error { return nil } +// UpdateTargetConfig updates the subscriptions for an existing target +func (a *App) UpdateTargetSubscription(ctx context.Context, name string, subs []string) error { + a.configLock.Lock() + for _, subName := range subs { + if _, ok := a.Config.Subscriptions[subName]; !ok { + a.configLock.Unlock() + return fmt.Errorf("subscription %q does not exist", subName) + } + } + targetConfig := a.Config.Targets[name] + targetConfig.Subscriptions = subs + a.configLock.Unlock() + + if err := a.stopTarget(ctx, name); err != nil { + return err + } + + go a.TargetSubscribeStream(ctx, targetConfig) + return nil +} + // AddTargetConfig adds a *TargetConfig to the configuration map func (a *App) AddTargetConfig(tc *types.TargetConfig) { a.Logger.Printf("adding target %s", tc)