• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-connect / 786634702

pending completion
786634702

Pull #96

gitlab-ci

Lluis Campos
ci: Remove trigger to `mender-dist-packages`
Pull Request #96: QA-542: ci: Remove trigger to `mender-dist-packages`

2456 of 3151 relevant lines covered (77.94%)

13.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.05
/app/daemon_shell.go
1
// Copyright 2022 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14
package app
15

16
import (
17
        "fmt"
18

19
        "github.com/mendersoftware/go-lib-micro/ws"
20
        wsshell "github.com/mendersoftware/go-lib-micro/ws/shell"
21
        "github.com/pkg/errors"
22
        log "github.com/sirupsen/logrus"
23

24
        "github.com/mendersoftware/mender-connect/config"
25
        "github.com/mendersoftware/mender-connect/procps"
26
        "github.com/mendersoftware/mender-connect/session"
27
        "github.com/mendersoftware/mender-connect/utils"
28
)
29

30
const (
31
        propertyTerminalHeight = "terminal_height"
32
        propertyTerminalWidth  = "terminal_width"
33
        propertyUserID         = "user_id"
34
)
35

36
func getUserIdFromMessage(message *ws.ProtoMsg) string {
14✔
37
        userID, _ := message.Header.Properties[propertyUserID].(string)
14✔
38
        return userID
14✔
39
}
14✔
40

41
func (d *MenderShellDaemon) routeMessageSpawnShell(message *ws.ProtoMsg) error {
16✔
42
        var err error
16✔
43
        response := &ws.ProtoMsg{
16✔
44
                Header: ws.ProtoHdr{
16✔
45
                        Proto:     message.Header.Proto,
16✔
46
                        MsgType:   message.Header.MsgType,
16✔
47
                        SessionID: message.Header.SessionID,
16✔
48
                        Properties: map[string]interface{}{
16✔
49
                                "status": wsshell.NormalMessage,
16✔
50
                        },
16✔
51
                },
16✔
52
                Body: []byte{},
16✔
53
        }
16✔
54
        if d.shellsSpawned >= config.MaxShellsSpawned {
18✔
55
                err = session.ErrSessionTooManyShellsAlreadyRunning
2✔
56
                d.routeMessageResponse(response, err)
2✔
57
                return err
2✔
58
        }
2✔
59
        s := session.MenderShellSessionGetById(message.Header.SessionID)
14✔
60
        if s == nil {
28✔
61
                userId := getUserIdFromMessage(message)
14✔
62
                if s, err = session.NewMenderShellSession(
14✔
63
                        message.Header.SessionID,
14✔
64
                        userId,
14✔
65
                        d.expireSessionsAfter,
14✔
66
                        d.expireSessionsAfterIdle,
14✔
67
                ); err != nil {
16✔
68
                        d.routeMessageResponse(response, err)
2✔
69
                        return err
2✔
70
                }
2✔
71
                log.Debugf("created a new session: %s", s.GetId())
12✔
72
        }
73

74
        response.Header.SessionID = s.GetId()
12✔
75

12✔
76
        terminalHeight := d.TerminalConfig.Height
12✔
77
        terminalWidth := d.TerminalConfig.Width
12✔
78

12✔
79
        requestedHeight, requestedWidth := mapPropertiesToTerminalHeightAndWidth(
12✔
80
                message.Header.Properties,
12✔
81
        )
12✔
82
        if requestedHeight > 0 && requestedWidth > 0 {
24✔
83
                terminalHeight = requestedHeight
12✔
84
                terminalWidth = requestedWidth
12✔
85
        }
12✔
86

87
        log.Debugf("starting shell session_id=%s", s.GetId())
12✔
88
        if err = s.StartShell(s.GetId(), session.MenderShellTerminalSettings{
12✔
89
                Uid:            uint32(d.uid),
12✔
90
                Gid:            uint32(d.gid),
12✔
91
                Shell:          d.shell,
12✔
92
                HomeDir:        d.homeDir,
12✔
93
                TerminalString: d.terminalString,
12✔
94
                Height:         terminalHeight,
12✔
95
                Width:          terminalWidth,
12✔
96
                ShellArguments: d.shellArguments,
12✔
97
        }); err != nil {
12✔
98
                err = errors.Wrap(err, "failed to start shell")
×
99
                d.routeMessageResponse(response, err)
×
100
                return err
×
101
        }
×
102

103
        log.Debug("Shell started")
12✔
104
        d.shellsSpawned++
12✔
105

12✔
106
        response.Body = []byte("Shell started")
12✔
107
        d.routeMessageResponse(response, err)
12✔
108
        return nil
12✔
109
}
110

111
func (d *MenderShellDaemon) routeMessageStopShell(message *ws.ProtoMsg) error {
8✔
112
        var err error
8✔
113
        response := &ws.ProtoMsg{
8✔
114
                Header: ws.ProtoHdr{
8✔
115
                        Proto:     message.Header.Proto,
8✔
116
                        MsgType:   message.Header.MsgType,
8✔
117
                        SessionID: message.Header.SessionID,
8✔
118
                        Properties: map[string]interface{}{
8✔
119
                                "status": wsshell.NormalMessage,
8✔
120
                        },
8✔
121
                },
8✔
122
                Body: []byte{},
8✔
123
        }
8✔
124

8✔
125
        if len(message.Header.SessionID) < 1 {
8✔
126
                userId := getUserIdFromMessage(message)
×
127
                if len(userId) < 1 {
×
128
                        err = errors.New("StopShellMessage: sessionId not given and userId empty")
×
129
                        d.routeMessageResponse(response, err)
×
130
                        return err
×
131
                }
×
132
                shellsStoppedCount, err := session.MenderShellStopByUserId(userId)
×
133
                if err == nil {
×
134
                        if shellsStoppedCount > d.shellsSpawned {
×
135
                                d.shellsSpawned = 0
×
136
                                err = errors.New(fmt.Sprintf("StopByUserId: the shells stopped count (%d) "+
×
137
                                        "greater than total shells spawned (%d). resetting shells "+
×
138
                                        "spawned to 0.", shellsStoppedCount, d.shellsSpawned))
×
139
                                d.routeMessageResponse(response, err)
×
140
                                return err
×
141
                        } else {
×
142
                                log.Debugf("StopByUserId: stopped %d shells.", shellsStoppedCount)
×
143
                                d.DecreaseSpawnedShellsCount(shellsStoppedCount)
×
144
                        }
×
145
                }
146
                d.routeMessageResponse(response, err)
×
147
                return err
×
148
        }
149

150
        s := session.MenderShellSessionGetById(message.Header.SessionID)
8✔
151
        if s == nil {
12✔
152
                err = errors.New(
4✔
153
                        fmt.Sprintf(
4✔
154
                                "routeMessage: StopShellMessage: session not found for id %s",
4✔
155
                                message.Header.SessionID,
4✔
156
                        ),
4✔
157
                )
4✔
158
                d.routeMessageResponse(response, err)
4✔
159
                return err
4✔
160
        }
4✔
161

162
        err = s.StopShell()
4✔
163
        if err != nil {
4✔
164
                if procps.ProcessExists(s.GetShellPid()) {
×
165
                        log.Errorf("could not terminate shell (pid %d) for session %s, user"+
×
166
                                "will not be able to start another one if the limit is reached.",
×
167
                                s.GetShellPid(),
×
168
                                s.GetId())
×
169
                        err = errors.New("could not terminate shell: " + err.Error() + ".")
×
170
                        d.routeMessageResponse(response, err)
×
171
                        return err
×
172
                } else {
×
173
                        log.Errorf("process error on exit: %s", err.Error())
×
174
                }
×
175
        }
176
        if d.shellsSpawned == 0 {
4✔
177
                log.Warn("can't decrement shellsSpawned count: it is 0.")
×
178
        } else {
4✔
179
                d.shellsSpawned--
4✔
180
        }
4✔
181
        err = session.MenderShellDeleteById(s.GetId())
4✔
182
        d.routeMessageResponse(response, err)
4✔
183
        return err
4✔
184
}
185

186
func (d *MenderShellDaemon) routeMessageShellCommand(message *ws.ProtoMsg) error {
6✔
187
        var err error
6✔
188
        response := &ws.ProtoMsg{
6✔
189
                Header: ws.ProtoHdr{
6✔
190
                        Proto:     message.Header.Proto,
6✔
191
                        MsgType:   message.Header.MsgType,
6✔
192
                        SessionID: message.Header.SessionID,
6✔
193
                        Properties: map[string]interface{}{
6✔
194
                                "status": wsshell.NormalMessage,
6✔
195
                        },
6✔
196
                },
6✔
197
                Body: []byte{},
6✔
198
        }
6✔
199

6✔
200
        s := session.MenderShellSessionGetById(message.Header.SessionID)
6✔
201
        if s == nil {
8✔
202
                err = session.ErrSessionNotFound
2✔
203
                d.routeMessageResponse(response, err)
2✔
204
                return err
2✔
205
        }
2✔
206
        err = s.ShellCommand(message)
4✔
207
        if err != nil {
4✔
208
                err = errors.Wrapf(
×
209
                        err,
×
210
                        "routeMessage: shell command execution error, session_id=%s",
×
211
                        message.Header.SessionID,
×
212
                )
×
213
                d.routeMessageResponse(response, err)
×
214
                return err
×
215
        }
×
216
        return nil
4✔
217
}
218

219
func mapPropertiesToTerminalHeightAndWidth(properties map[string]interface{}) (uint16, uint16) {
12✔
220
        var terminalHeight, terminalWidth uint16
12✔
221
        requestedHeight, requestedHeightOk := properties[propertyTerminalHeight]
12✔
222
        requestedWidth, requestedWidthOk := properties[propertyTerminalWidth]
12✔
223
        if requestedHeightOk && requestedWidthOk {
24✔
224
                if val, _ := utils.Num64(requestedHeight); val > 0 {
24✔
225
                        terminalHeight = uint16(val)
12✔
226
                }
12✔
227
                if val, _ := utils.Num64(requestedWidth); val > 0 {
24✔
228
                        terminalWidth = uint16(val)
12✔
229
                }
12✔
230
        }
231
        return terminalHeight, terminalWidth
12✔
232
}
233

234
func (d *MenderShellDaemon) routeMessageShellResize(message *ws.ProtoMsg) error {
×
235
        var err error
×
236

×
237
        s := session.MenderShellSessionGetById(message.Header.SessionID)
×
238
        if s == nil {
×
239
                err = session.ErrSessionNotFound
×
240
                log.Errorf(err.Error())
×
241
                return err
×
242
        }
×
243

244
        terminalHeight, terminalWidth := mapPropertiesToTerminalHeightAndWidth(
×
245
                message.Header.Properties,
×
246
        )
×
247
        if terminalHeight > 0 && terminalWidth > 0 {
×
248
                s.ResizeShell(terminalHeight, terminalWidth)
×
249
        }
×
250
        return nil
×
251
}
252

253
func (d *MenderShellDaemon) routeMessagePongShell(message *ws.ProtoMsg) error {
×
254
        var err error
×
255

×
256
        s := session.MenderShellSessionGetById(message.Header.SessionID)
×
257
        if s == nil {
×
258
                err = session.ErrSessionNotFound
×
259
                log.Errorf(err.Error())
×
260
                return err
×
261
        }
×
262

263
        s.HealthcheckPong()
×
264
        return nil
×
265
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc