44package self
55
66import (
7+ "context"
78 "encoding/json"
89 "fmt"
910 "log/slog"
11+ "strings"
1012
1113 "github.com/spf13/cobra"
1214 "github.com/thin-edge/tedge-container-plugin/pkg/cli"
15+ "github.com/thin-edge/tedge-container-plugin/pkg/container"
1316)
1417
1518type SoftwareModule struct {
@@ -18,14 +21,16 @@ type SoftwareModule struct {
1821}
1922
2023type SoftwareItem struct {
21- Action string `json:"action,omitempty"`
2224 Name string `json:"name,omitempty"`
2325 Version string `json:"version,omitempty"`
26+ Url string `json:"url,omitempty"`
27+ Action string `json:"action,omitempty"`
2428}
2529
2630type UpdateInfo struct {
27- ContainerName string `json:"containerName"`
28- Image string `json:"image"`
31+ ContainerName string `json:"containerName"`
32+ Image string `json:"image"`
33+ UpdateList []SoftwareModule `json:"updateList"`
2934}
3035
3136var ExitYes = 0
@@ -39,56 +44,129 @@ func newUnexpectedError(err error) error {
3944 }
4045}
4146
42- var SoftwareManagementType = "self"
47+ var SoftwareManagementTypeSelf = "self"
48+ var SoftwareManagementTypeContainer = "container"
4349var SoftwareManagementActionInstall = "install"
50+ var SoftwareManagementActionRemove = "remove"
51+
52+ type CheckCommand struct {
53+ * cobra.Command
54+
55+ ContainerName string
56+ }
4457
4558// NewCheckCommand represents the check command
4659func NewCheckCommand (ctx cli.Cli ) * cobra.Command {
47- return & cobra.Command {
60+ command := & CheckCommand {}
61+ cmd := & cobra.Command {
4862 Use : "check" ,
4963 Args : cobra .ExactArgs (1 ),
5064 Short : "Check if an update is required (not part of sm-plugin interface!)" ,
51- RunE : func (cmd * cobra.Command , args []string ) error {
52- slog .Info ("Executing" , "cmd" , cmd .CalledAs (), "args" , args )
65+ RunE : command .RunE ,
66+ }
67+ cmd .Flags ().StringVar (& command .ContainerName , "container" , "" , "Set current container name" )
68+ command .Command = cmd
69+ return command .Command
70+ }
5371
54- updateList := make ([]SoftwareModule , 0 )
55- if err := json .Unmarshal ([]byte (args [0 ]), & updateList ); err != nil {
56- return newUnexpectedError (err )
57- }
72+ func (c * CheckCommand ) RunE (cmd * cobra.Command , args []string ) error {
73+ slog .Info ("Executing" , "cmd" , cmd .CalledAs (), "args" , args )
5874
59- includesSelfUpdate := false
60-
61- match := UpdateInfo {}
62- for _ , module := range updateList {
63- if module .Type == SoftwareManagementType {
64- for _ , item := range module .Modules {
65- if item .Action == SoftwareManagementActionInstall {
66- match .ContainerName = item .Name
67- match .Image = item .Version
68- includesSelfUpdate = true
69- break
70- }
75+ updateList := make ([]SoftwareModule , 0 )
76+ if err := json .Unmarshal ([]byte (args [0 ]), & updateList ); err != nil {
77+ return newUnexpectedError (err )
78+ }
79+
80+ // Check container self
81+ containerCLI , err := container .NewContainerClient ()
82+ if err != nil {
83+ return err
84+ }
85+
86+ ctx := context .Background ()
87+
88+ selfContainerName := c .ContainerName
89+ selfContainerID := ""
90+ if con , err := containerCLI .Self (ctx ); err == nil {
91+ selfContainerName = strings .TrimPrefix (con .Name , "/" )
92+ selfContainerID = con .ID
93+ } else if selfContainerName == "" {
94+ slog .Info ("self container." , "err" , err )
95+ }
96+
97+ includesSelfUpdate := false
98+ outputUpdateModules := make ([]SoftwareModule , 0 )
99+
100+ match := UpdateInfo {}
101+ for _ , module := range updateList {
102+ if module .Type == SoftwareManagementTypeSelf {
103+ // self update (to be removed in the future)
104+ for _ , item := range module .Modules {
105+ if item .Action == SoftwareManagementActionInstall {
106+ match .ContainerName = item .Name
107+ match .Image = item .Version
108+ includesSelfUpdate = true
109+ } else if item .Action == SoftwareManagementActionRemove {
110+ return cli.ExitCodeError {
111+ Code : ExitError ,
112+ Err : fmt .Errorf ("tedge's own container cannot be removed. name=%s, version=%s, containerId=%s" , item .Name , item .Version , selfContainerID ),
113+ Silent : true ,
71114 }
72- break
73115 }
74116 }
117+ } else if module .Type == SoftwareManagementTypeContainer {
118+ // container update
119+ // Filter non self-updated modules
120+ filteredModules := make ([]SoftwareItem , 0 )
75121
76- if ! includesSelfUpdate {
77- return cli.ExitCodeError {
78- Code : ExitNo ,
79- Silent : true ,
122+ for _ , item := range module .Modules {
123+ if selfContainerName == item .Name {
124+ if item .Action == SoftwareManagementActionRemove {
125+ // Protect against the user deleting the tedge container itself
126+ return cli.ExitCodeError {
127+ Code : ExitError ,
128+ Err : fmt .Errorf ("tedge's own container cannot be removed. name=%s, version=%s, containerId=%s" , item .Name , item .Version , selfContainerID ),
129+ Silent : true ,
130+ }
131+ } else if item .Action == SoftwareManagementActionInstall {
132+ // install
133+ match .ContainerName = item .Name
134+ match .Image = item .Version
135+ includesSelfUpdate = true
136+ }
137+ } else {
138+ filteredModules = append (filteredModules , item )
80139 }
81140 }
82-
83- slog . Info ( "Update included a self update" )
84- payload , err := json . Marshal ( match )
85- if err != nil {
86- return newUnexpectedError ( err )
141+ if len ( filteredModules ) > 0 {
142+ outputUpdateModules = append ( outputUpdateModules , SoftwareModule {
143+ Type : module . Type ,
144+ Modules : filteredModules ,
145+ } )
87146 }
88- fmt .Fprintf (cmd .OutOrStdout (), ":::begin-tedge:::\n %s\n :::end-tedge:::\n " , payload )
147+ } else {
148+ outputUpdateModules = append (outputUpdateModules , module )
149+ }
150+ }
151+
152+ match .UpdateList = outputUpdateModules
89153
90- // includes self update
91- return nil
92- },
154+ // Check if the container is itself
155+ if ! includesSelfUpdate {
156+ return cli.ExitCodeError {
157+ Code : ExitNo ,
158+ Err : fmt .Errorf ("no self-update detected" ),
159+ Silent : true ,
160+ }
93161 }
162+
163+ slog .Info ("Update included a self update" )
164+ payload , err := json .Marshal (match )
165+ if err != nil {
166+ return newUnexpectedError (err )
167+ }
168+ fmt .Fprintf (cmd .OutOrStdout (), ":::begin-tedge:::\n %s\n :::end-tedge:::\n " , payload )
169+
170+ // includes self update
171+ return nil
94172}
0 commit comments