Skip to content

Commit d9c4fb9

Browse files
committed
add serial number for network discovery
1 parent a2f7219 commit d9c4fb9

File tree

2 files changed

+212
-0
lines changed

2 files changed

+212
-0
lines changed

pkg/board/board.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,12 @@ func EnableNetworkMode(ctx context.Context, conn remote.RemoteConn) error {
354354
{"sudo", "systemctl", "start", "avahi-daemon"},
355355
}
356356

357+
if sn, err := getSerial(&local.LocalConnection{}); err == nil {
358+
if err := setSerialNumber(sn, "/etc/avahi/services/arduino.service"); err != nil {
359+
slog.Warn("failed to set serial number for network mode", slog.Any("error", err))
360+
}
361+
}
362+
357363
for _, cmd := range cmds {
358364
if out, err := conn.GetCmd(cmd[0], cmd[1:]...).Output(ctx); err != nil {
359365
return fmt.Errorf("failed to run cmd %q: %w: %s", strings.Join(cmd, " "), err, string(out))
@@ -363,6 +369,40 @@ func EnableNetworkMode(ctx context.Context, conn remote.RemoteConn) error {
363369
return nil
364370
}
365371

372+
func setSerialNumber(serialNumber, filePath string) error {
373+
serialCheckRegex := regexp.MustCompile(`<\s*txt-record\s*>\s*serial_number=\S+\s*<\s*/txt-record\s*>`)
374+
serviceEndTag := regexp.MustCompile(`</service>`)
375+
newSerialTemplate := `<txt-record>serial_number=%s</txt-record>
376+
`
377+
if serialNumber == "" {
378+
return errors.New("missing or empty serial number")
379+
}
380+
381+
data, err := os.ReadFile(filePath)
382+
if err != nil {
383+
if os.IsNotExist(err) {
384+
return nil
385+
}
386+
return err
387+
}
388+
389+
if serialCheckRegex.Match(data) {
390+
return nil
391+
}
392+
393+
loc := serviceEndTag.FindIndex(data)
394+
if loc == nil {
395+
return errors.New(" </service> tag not found in the service file")
396+
}
397+
398+
var buf bytes.Buffer
399+
buf.Write(data[:loc[0]])
400+
buf.WriteString(fmt.Sprintf(newSerialTemplate, serialNumber))
401+
buf.Write(data[loc[0]:])
402+
403+
return os.WriteFile(filePath, buf.Bytes(), 0600)
404+
}
405+
366406
func NetworkModeStatus(ctx context.Context, conn remote.RemoteConn) (bool, error) {
367407
cmds := [][]string{
368408
{"systemctl", "is-enabled", "ssh"},

pkg/board/board_test.go

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,175 @@ func TestEnsurePlatformInstalled(t *testing.T) {
3131
err := EnsurePlatformInstalled(t.Context(), "arduino:zephyr:unoq")
3232
require.NoError(t, err)
3333
}
34+
35+
func TestSetSerialNumber(t *testing.T) {
36+
37+
testCases := []struct {
38+
name string
39+
initialContent string
40+
serialNumber string
41+
expectedErr bool
42+
expectedContent string
43+
}{
44+
{
45+
name: "Non-existing file",
46+
initialContent: "",
47+
serialNumber: "123456789",
48+
expectedErr: false,
49+
expectedContent: "",
50+
},
51+
{
52+
name: "Non-existing serial number",
53+
initialContent: `<?xml version="1.0" standalone='no'?>
54+
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
55+
<service-group>
56+
<name replace-wildcards="yes">%h</name>
57+
<service>
58+
<type>_arduino._tcp</type>
59+
<port>80</port>
60+
<txt-record>board=unoq</txt-record>
61+
<txt-record>vid=0x2341</txt-record>
62+
<txt-record>pid=0x0078</txt-record>
63+
<txt-record>vid.0=0x2341</txt-record>
64+
<txt-record>pid.0=0x0078</txt-record>
65+
<txt-record>distro_version=0.1</txt-record>
66+
<txt-record>ssh_upload=no</txt-record>
67+
<txt-record>tcp_check=no</txt-record>
68+
<txt-record>auth_upload=yes</txt-record>
69+
</service>
70+
</service-group>
71+
`,
72+
serialNumber: "123456789",
73+
expectedErr: false,
74+
expectedContent: `<?xml version="1.0" standalone='no'?>
75+
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
76+
<service-group>
77+
<name replace-wildcards="yes">%h</name>
78+
<service>
79+
<type>_arduino._tcp</type>
80+
<port>80</port>
81+
<txt-record>board=unoq</txt-record>
82+
<txt-record>vid=0x2341</txt-record>
83+
<txt-record>pid=0x0078</txt-record>
84+
<txt-record>vid.0=0x2341</txt-record>
85+
<txt-record>pid.0=0x0078</txt-record>
86+
<txt-record>distro_version=0.1</txt-record>
87+
<txt-record>ssh_upload=no</txt-record>
88+
<txt-record>tcp_check=no</txt-record>
89+
<txt-record>auth_upload=yes</txt-record>
90+
<txt-record>serial_number=123456789</txt-record>
91+
</service>
92+
</service-group>
93+
`,
94+
},
95+
{
96+
name: "serial number not provided",
97+
initialContent: `<?xml version="1.0" standalone='no'?>
98+
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
99+
<service-group>
100+
<name replace-wildcards="yes">%h</name>
101+
<service>
102+
<type>_arduino._tcp</type>
103+
<port>80</port>
104+
<txt-record>board=unoq</txt-record>
105+
</service>
106+
</service-group>
107+
`,
108+
serialNumber: "",
109+
expectedErr: true,
110+
expectedContent: ``,
111+
},
112+
{
113+
name: "serial number already present",
114+
initialContent: `<?xml version="1.0" standalone='no'?>
115+
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
116+
<service-group>
117+
<name replace-wildcards="yes">%h</name>
118+
<service>
119+
<type>_arduino._tcp</type>
120+
<port>80</port>
121+
<txt-record>board=unoq</txt-record>
122+
<txt-record>vid=0x2341</txt-record>
123+
<txt-record>pid=0x0078</txt-record>
124+
<txt-record>vid.0=0x2341</txt-record>
125+
<txt-record>pid.0=0x0078</txt-record>
126+
<txt-record>distro_version=0.1</txt-record>
127+
<txt-record>ssh_upload=no</txt-record>
128+
<txt-record>tcp_check=no</txt-record>
129+
<txt-record>auth_upload=yes</txt-record>
130+
<txt-record>serial_number=123456789</txt-record>
131+
</service>
132+
</service-group>
133+
`,
134+
serialNumber: "111111111",
135+
expectedErr: false,
136+
expectedContent: `<?xml version="1.0" standalone='no'?>
137+
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
138+
<service-group>
139+
<name replace-wildcards="yes">%h</name>
140+
<service>
141+
<type>_arduino._tcp</type>
142+
<port>80</port>
143+
<txt-record>board=unoq</txt-record>
144+
<txt-record>vid=0x2341</txt-record>
145+
<txt-record>pid=0x0078</txt-record>
146+
<txt-record>vid.0=0x2341</txt-record>
147+
<txt-record>pid.0=0x0078</txt-record>
148+
<txt-record>distro_version=0.1</txt-record>
149+
<txt-record>ssh_upload=no</txt-record>
150+
<txt-record>tcp_check=no</txt-record>
151+
<txt-record>auth_upload=yes</txt-record>
152+
<txt-record>serial_number=123456789</txt-record>
153+
</service>
154+
</service-group>
155+
`,
156+
},
157+
{
158+
name: "missing service tag",
159+
initialContent: `<?xml version="1.0" standalone='no'?>
160+
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
161+
<service-group>
162+
<name replace-wildcards="yes">%h</name>
163+
<service>
164+
<type>_arduino._tcp</type>
165+
<port>80</port>
166+
`,
167+
serialNumber: "111111111",
168+
expectedErr: true,
169+
expectedContent: ``,
170+
},
171+
}
172+
173+
for _, tc := range testCases {
174+
t.Run(tc.name, func(t *testing.T) {
175+
tmpFile, err := os.CreateTemp("", "arduino.service.*.xml")
176+
require.NoError(t, err)
177+
filePath := tmpFile.Name()
178+
defer os.Remove(filePath)
179+
180+
if tc.initialContent != "" {
181+
_, err = tmpFile.WriteString(tc.initialContent)
182+
require.NoError(t, err)
183+
}
184+
tmpFile.Close()
185+
186+
if tc.initialContent == "" {
187+
err = os.Remove(filePath)
188+
require.NoError(t, err)
189+
err = setSerialNumber(tc.serialNumber, filePath)
190+
require.NoError(t, err)
191+
return
192+
}
193+
194+
err = setSerialNumber(tc.serialNumber, filePath)
195+
if tc.expectedErr {
196+
require.Error(t, err)
197+
} else {
198+
require.NoError(t, err)
199+
updatedContent, err := os.ReadFile(filePath)
200+
require.NoError(t, err)
201+
require.Equal(t, tc.expectedContent, string(updatedContent))
202+
}
203+
})
204+
}
205+
}

0 commit comments

Comments
 (0)