forked from ooni/probe-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtaskmodel.go
374 lines (311 loc) · 12 KB
/
taskmodel.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
package oonimkall
import (
"context"
"io"
"github.com/ooni/probe-cli/v3/internal/engine"
"github.com/ooni/probe-cli/v3/internal/model"
)
//
// Task Model
//
// The oonimkall package allows you to run OONI network
// experiments as "tasks". This file defines all the
// underlying model entailed by running such tasks.
//
// Logging
//
// This section of the file defines the types and the
// interfaces required to implement logging.
//
// The rest of the codebase will use a generic model.Logger
// as a logger. This is a pretty fundamental interface in
// ooni/probe-cli and so it's not defined in this file.
//
const taskABIVersion = 1
// Running tasks emit logs using different log levels. We
// define log levels with the usual semantics.
//
// The logger used by a task _may_ be configured to not
// emit log events that are less severe than a given
// severity.
//
// We use the following definitions both for defining the
// log level of a log and for configuring the maximum
// acceptable log level emitted by a logger.
const (
logLevelDebug2 = "DEBUG2"
logLevelDebug = "DEBUG"
logLevelInfo = "INFO"
logLevelErr = "ERR"
logLevelWarning = "WARNING"
)
//
// Emitting Events
//
// While it is running, a task emits events. This section
// of the file defines the types needed to emit events.
//
// type of emitted events.
const (
eventTypeFailureIPLookup = "failure.ip_lookup"
eventTypeFailureASNLookup = "failure.asn_lookup"
eventTypeFailureCCLookup = "failure.cc_lookup"
eventTypeFailureMeasurement = "failure.measurement"
eventTypeFailureMeasurementSubmission = "failure.measurement_submission"
eventTypeFailureReportCreate = "failure.report_create"
eventTypeFailureResolverLookup = "failure.resolver_lookup"
eventTypeFailureStartup = "failure.startup"
eventTypeLog = "log"
eventTypeMeasurement = "measurement"
eventTypeStatusEnd = "status.end"
eventTypeStatusGeoIPLookup = "status.geoip_lookup"
eventTypeStatusMeasurementDone = "status.measurement_done"
eventTypeStatusMeasurementStart = "status.measurement_start"
eventTypeStatusMeasurementSubmission = "status.measurement_submission"
eventTypeStatusProgress = "status.progress"
eventTypeStatusQueued = "status.queued"
eventTypeStatusReportCreate = "status.report_create"
eventTypeStatusResolverLookup = "status.resolver_lookup"
eventTypeStatusStarted = "status.started"
)
// taskEmitter is anything that allows us to
// emit events while running a task.
//
// Note that a task emitter _may_ be configured
// to ignore _some_ events though.
type taskEmitter interface {
// Emit emits the event (unless the emitter is
// configured to ignore this event key).
Emit(key string, value interface{})
}
// taskEmitterCloser is a closeable taskEmitter.
type taskEmitterCloser interface {
taskEmitter
io.Closer
}
type eventEmpty struct{}
// eventFailure contains information on a failure.
type eventFailure struct {
Failure string `json:"failure"`
}
// eventLog is an event containing a log message.
type eventLog struct {
LogLevel string `json:"log_level"`
Message string `json:"message"`
}
type eventMeasurementGeneric struct {
Failure string `json:"failure,omitempty"`
Idx int64 `json:"idx"`
Input string `json:"input"`
JSONStr string `json:"json_str,omitempty"`
}
type eventStatusEnd struct {
DownloadedKB float64 `json:"downloaded_kb"`
Failure string `json:"failure"`
UploadedKB float64 `json:"uploaded_kb"`
}
type eventStatusGeoIPLookup struct {
ProbeASN string `json:"probe_asn"`
ProbeCC string `json:"probe_cc"`
ProbeIP string `json:"probe_ip"`
ProbeNetworkName string `json:"probe_network_name"`
}
// eventStatusProgress reports progress information.
type eventStatusProgress struct {
Message string `json:"message"`
Percentage float64 `json:"percentage"`
}
type eventStatusReportGeneric struct {
ReportID string `json:"report_id"`
}
type eventStatusResolverLookup struct {
ResolverASN string `json:"resolver_asn"`
ResolverIP string `json:"resolver_ip"`
ResolverNetworkName string `json:"resolver_network_name"`
}
// event is an event emitted by a task. This structure extends the event
// described by MK v0.10.9 FFI API (https://git.io/Jv4Rv).
type event struct {
Key string `json:"key"`
Value interface{} `json:"value"`
}
//
// OONI Session
//
// For performing several operations, including running
// experiments, we need to create an OONI session.
//
// This section of the file defines the interface between
// our oonimkall API and the real session.
//
// The abstraction representing a OONI session is taskSession.
//
// taskKVStoreFSBuilder constructs a KVStore with
// filesystem backing for running tests.
type taskKVStoreFSBuilder interface {
// NewFS creates a new KVStore using the filesystem.
NewFS(path string) (model.KeyValueStore, error)
}
// taskSessionBuilder constructs a new Session.
type taskSessionBuilder interface {
// NewSession creates a new taskSession.
NewSession(ctx context.Context,
config engine.SessionConfig) (taskSession, error)
}
// taskSession abstracts a OONI session.
type taskSession interface {
// A session can be closed.
io.Closer
// NewExperimentBuilderByName creates the builder for constructing
// a new experiment given the experiment's name.
NewExperimentBuilderByName(name string) (taskExperimentBuilder, error)
// MaybeLookupBackendsContext lookups the OONI backend unless
// this operation has already been performed.
MaybeLookupBackendsContext(ctx context.Context) error
// MaybeLookupLocationContext lookups the probe location unless
// this operation has already been performed.
MaybeLookupLocationContext(ctx context.Context) error
// ProbeIP must be called after MaybeLookupLocationContext
// and returns the resolved probe IP.
ProbeIP() string
// ProbeASNString must be called after MaybeLookupLocationContext
// and returns the resolved probe ASN as a string.
ProbeASNString() string
// ProbeCC must be called after MaybeLookupLocationContext
// and returns the resolved probe country code.
ProbeCC() string
// ProbeNetworkName must be called after MaybeLookupLocationContext
// and returns the resolved probe country code.
ProbeNetworkName() string
// ResolverANSString must be called after MaybeLookupLocationContext
// and returns the resolved resolver's ASN as a string.
ResolverASNString() string
// ResolverIP must be called after MaybeLookupLocationContext
// and returns the resolved resolver's IP.
ResolverIP() string
// ResolverNetworkName must be called after MaybeLookupLocationContext
// and returns the resolved resolver's network name.
ResolverNetworkName() string
}
// taskExperimentBuilder builds a taskExperiment.
type taskExperimentBuilder interface {
// SetCallbacks sets the experiment callbacks.
SetCallbacks(callbacks model.ExperimentCallbacks)
// InputPolicy returns the experiment's input policy.
InputPolicy() model.InputPolicy
// NewExperiment creates the new experiment.
NewExperimentInstance() taskExperiment
// Interruptible returns whether this experiment is interruptible.
Interruptible() bool
}
// taskExperiment is a runnable experiment.
type taskExperiment interface {
// KibiBytesReceived returns the KiB received by the experiment.
KibiBytesReceived() float64
// KibiBytesSent returns the KiB sent by the experiment.
KibiBytesSent() float64
// OpenReportContext opens a new report.
OpenReportContext(ctx context.Context) error
// ReportID must be called after a successful OpenReportContext
// and returns the report ID for this measurement.
ReportID() string
// MeasureWithContext runs the measurement.
MeasureWithContext(ctx context.Context, target model.ExperimentTarget) (
measurement *model.Measurement, err error)
// SubmitAndUpdateMeasurementContext submits the measurement
// and updates its report ID on success.
SubmitAndUpdateMeasurementContext(
ctx context.Context, measurement *model.Measurement) error
}
//
// Task Running
//
// This section contains the interfaces allowing us
// to run a task until completion.
//
// taskRunner runs a task until completion.
type taskRunner interface {
// Run runs until completion.
Run(ctx context.Context)
}
//
// Task Settings
//
// This section defines the settings used by a task.
//
// Settings contains settings for a task. This structure derives from
// the one described by MK v0.10.9 FFI API (https://git.io/Jv4Rv), yet
// since 2020-12-03 we're not backwards compatible anymore.
type settings struct {
// Annotations contains the annotations to be added
// to every measurements performed by the task.
Annotations map[string]string `json:"annotations,omitempty"`
// AssetsDir is the directory where to store assets. This
// field is an extension of MK's specification. If
// this field is empty, the task won't start.
AssetsDir string `json:"assets_dir"`
// DisabledEvents contains disabled events. See
// https://git.io/Jv4Rv for the events names.
//
// This setting is currently ignored. We noticed the
// code was ignoring it on 2021-12-01.
DisabledEvents []string `json:"disabled_events,omitempty"`
// Inputs contains the inputs. The task will fail if it
// requires input and you provide no input.
Inputs []string `json:"inputs,omitempty"`
// LogLevel contains the logs level. See https://git.io/Jv4Rv
// for the names of the available log levels.
LogLevel string `json:"log_level,omitempty"`
// Name contains the task name. By https://git.io/Jv4Rv the
// names are in camel case, e.g. `Ndt`.
Name string `json:"name"`
// Options contains the task options.
Options settingsOptions `json:"options"`
// Proxy allows you to optionally force a specific proxy
// rather than using no proxy (the default).
//
// Use `psiphon:///` to force using Psiphon with the
// embedded configuration file. Not all builds have
// an embedded configuration file, but OONI builds have
// such a file, so they can use this functionality.
//
// Use `socks5://10.0.0.1:9050/` to connect to a SOCKS5
// proxy running on 10.0.0.1:9050. This could be, for
// example, a suitably configured `tor` instance.
Proxy string
// StateDir is the directory where to store persistent data. This
// field is an extension of MK's specification. If
// this field is empty, the task won't start.
StateDir string `json:"state_dir"`
// TempDir is the temporary directory. This field is an extension of MK's
// specification. If this field is empty, we will pick the tempdir that
// ioutil.TempDir uses by default, which may not work on mobile. According
// to our experiments as of 2020-06-10, leaving the TempDir empty works
// for iOS and does not work for Android.
TempDir string `json:"temp_dir"`
// TunnelDir is the directory where to store persistent state
// related to circumvention tunnels. This directory is required
// only if you want to use the tunnels. Added since 3.10.0.
TunnelDir string `json:"tunnel_dir"`
// Version indicates the version of this structure.
Version int64 `json:"version"`
}
// settingsOptions contains the settings options
type settingsOptions struct {
// MaxRuntime is the maximum runtime expressed in seconds. A negative
// value for this field disables the maximum runtime. Using
// a zero value will also mean disabled. This is not the
// original behaviour of Measurement Kit, which used to run
// for zero time in such case.
MaxRuntime float64 `json:"max_runtime,omitempty"`
// NoCollector indicates whether to use a collector
NoCollector bool `json:"no_collector,omitempty"`
// ProbeServicesBaseURL contains the probe services base URL.
ProbeServicesBaseURL string `json:"probe_services_base_url,omitempty"`
// SoftwareName is the software name. If this option is not
// present, then the library startup will fail.
SoftwareName string `json:"software_name,omitempty"`
// SoftwareVersion is the software version. If this option is not
// present, then the library startup will fail.
SoftwareVersion string `json:"software_version,omitempty"`
}