github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/daemon/api_console_conf.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2020 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package daemon
    21  
    22  import (
    23  	"encoding/json"
    24  	"io"
    25  	"net/http"
    26  	"time"
    27  
    28  	"github.com/snapcore/snapd/logger"
    29  	"github.com/snapcore/snapd/overlord/auth"
    30  )
    31  
    32  var (
    33  	routineConsoleConfStartCmd = &Command{
    34  		Path:        "/v2/internal/console-conf-start",
    35  		POST:        consoleConfStartRoutine,
    36  		WriteAccess: authenticatedAccess{},
    37  	}
    38  )
    39  
    40  var delayTime = 20 * time.Minute
    41  
    42  // consoleConfStartRoutineResult is the result of running the console-conf start
    43  // routine..
    44  type consoleConfStartRoutineResult struct {
    45  	ActiveAutoRefreshChanges []string `json:"active-auto-refreshes,omitempty"`
    46  	ActiveAutoRefreshSnaps   []string `json:"active-auto-refresh-snaps,omitempty"`
    47  }
    48  
    49  func consoleConfStartRoutine(c *Command, r *http.Request, _ *auth.UserState) Response {
    50  	// no body expected, error if we were provided anything
    51  	defer r.Body.Close()
    52  	var routineBody struct{}
    53  	decoder := json.NewDecoder(r.Body)
    54  	if err := decoder.Decode(&routineBody); err != nil && err != io.EOF {
    55  		return BadRequest("cannot decode request body into console-conf operation: %v", err)
    56  	}
    57  
    58  	// now run the start routine first by trying to grab a lock on the refreshes
    59  	// for all snaps, which fails if there are any active changes refreshing
    60  	// snaps
    61  	st := c.d.overlord.State()
    62  	st.Lock()
    63  	defer st.Unlock()
    64  
    65  	snapAutoRefreshChanges, err := c.d.overlord.SnapManager().EnsureAutoRefreshesAreDelayed(delayTime)
    66  	if err != nil {
    67  		return InternalError(err.Error())
    68  	}
    69  
    70  	logger.Debugf("Ensured that new auto refreshes are delayed by %s to allow console-conf to run", delayTime)
    71  
    72  	if len(snapAutoRefreshChanges) == 0 {
    73  		// no changes yet, and we delayed the refresh successfully so
    74  		// console-conf is okay to run normally
    75  		return SyncResponse(&consoleConfStartRoutineResult{})
    76  	}
    77  
    78  	chgIds := make([]string, 0, len(snapAutoRefreshChanges))
    79  	snapNames := make([]string, 0)
    80  	for _, chg := range snapAutoRefreshChanges {
    81  		chgIds = append(chgIds, chg.ID())
    82  		var updatedSnaps []string
    83  		err := chg.Get("snap-names", &updatedSnaps)
    84  		if err != nil {
    85  			return InternalError(err.Error())
    86  		}
    87  		snapNames = append(snapNames, updatedSnaps...)
    88  	}
    89  
    90  	// we have changes that the client should wait for before being ready
    91  	return SyncResponse(&consoleConfStartRoutineResult{
    92  		ActiveAutoRefreshChanges: chgIds,
    93  		ActiveAutoRefreshSnaps:   snapNames,
    94  	})
    95  
    96  }