scalable-pypeline 1.1.5__py2.py3-none-any.whl → 1.2.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pypeline/sermos_yaml.py CHANGED
@@ -3,59 +3,11 @@ managed deployments through Sermos.ai. If self-hosting, safely disregard this
3
3
  yaml format, no `sermos.yaml` is required for your application.
4
4
 
5
5
  If using, a basic file may look like::
6
-
7
- imageConfig:
8
- - name: base-image
9
- installCommand: sermos-demo-client[core]
10
- - name: public-api-image
11
- repositoryUrl: myregistry/public-api-image
12
-
13
- environmentVariables:
14
- - name: GLOBAL_ENV_VAR
15
- value: globally-available-env-var
16
-
17
6
  serviceConfig:
18
- - name: base-worker
19
- serviceType: celery-worker
20
- imageName: base-image
21
- queue: default-queue
22
- registeredTasks:
23
- - handler: sermos_demo_client.workers.demo_worker.demo_task
24
-
25
-
26
- imageConfig:
27
- - name: base-image
28
- installCommand: sermos-demo-client
29
- sourceSshUrl: git@gitlab.com:sermos/sermos-demo-client.git
30
- baseImage: registry.gitlab.com/sermos/sermos-tools:0.3.0
31
-
32
- serviceConfig:
33
- - name: demo-api
34
- serviceType: external
35
- serviceId: ${SERVICE_ID_API} # Rendered using `sermos deploy` if available in the environment.
36
- imageName: base-image
37
- command: gunicorn --log-level info -k gevent -b 0.0.0.0:5000 sermos_demo_client.app:create_app()
38
- port: 5000
39
- replicaCount: 1
40
- cpuLimit: 0.5
41
- memoryLimit: 0.5
42
- environmentVariables:
43
- - name: FLASK_SECRET_KEY
44
- value: ${FLASK_SECRET_KEY}
45
7
  - name: sermos-worker
46
- serviceType: celery-worker
47
- serviceId: ${SERVICE_ID_WORKER}
48
- imageName: base-image
49
- command: celery -A sermos_demo_client.celery worker --without-gossip --without-mingle -c '1' -l INFO --queue default-task-queue
50
- replicaCount: 1
51
- cpuLimit: 0.5
52
- memoryLimit: 0.5
53
8
  registeredTasks:
54
9
  - handler: sermos_demo_client.workers.demo_worker.demo_worker_task
55
10
  - handler: sermos_demo_client.workers.demo_worker.demo_model_task
56
- environmentVariables:
57
- - name: WORKER_NAME
58
- value: sermos-worker
59
11
 
60
12
  pipelines:
61
13
  demo-pipeline:
@@ -124,77 +76,11 @@ class MissingSermosConfig(Exception):
124
76
  pass
125
77
 
126
78
 
127
- class InvalidImageConfig(Exception):
128
- pass
129
-
130
-
131
79
  class ExcludeUnknownSchema(Schema):
132
80
  class Meta:
133
81
  unknown = EXCLUDE
134
82
 
135
83
 
136
- class EnvironmentVariableSchema(ExcludeUnknownSchema):
137
- """ A single environment variables (singular)
138
- """
139
- name = fields.String(required=True,
140
- description="Environment variable name.",
141
- example="MY_ENV_VAR")
142
- value = fields.String(required=True,
143
- description="Environment variable value.",
144
- example="my special value")
145
-
146
-
147
- class EnvironmentVariablesSchema(Schema):
148
- """ Multiple environment variables (plural)
149
- """
150
- environmentVariables = fields.List(
151
- fields.Nested(EnvironmentVariableSchema, required=True),
152
- description="List of name/value environment variable pairs available "
153
- "to the scope of this service.",
154
- required=False)
155
-
156
-
157
- class ServiceRequestsSchema(Schema):
158
-
159
- replicaCount = fields.Integer(
160
- required=False,
161
- description="Baseline (min) scale of this service to have available.",
162
- default=1,
163
- example=1)
164
- cpuRequest = fields.Float(
165
- required=False,
166
- description="Requested CPUs to be available for each replica.",
167
- default=0.5,
168
- example="0.5")
169
- memoryRequest = fields.Float(
170
- required=False,
171
- description="Requested memory (in GB) to be available for each replica.",
172
- default=0.5,
173
- example="0.5 (means half of 1 GB)")
174
- ephemeralStorageRequest = fields.Float(
175
- required=False,
176
- description="Requested ephemeral storage (in GB) to "
177
- "be available for each replica.",
178
- default=8,
179
- example="2 (means 2 GB)")
180
- cpuLimit = fields.Float(
181
- required=False,
182
- description="Maximum CPUs to be available for each replica.",
183
- default=0.5,
184
- example="0.5")
185
- memoryLimit = fields.Float(
186
- required=False,
187
- description="Maximum memory (in GB) to be available for each replica.",
188
- default=0.5,
189
- example="0.5 (means half of 1 GB)")
190
- ephemeralStorageLimit = fields.Float(
191
- required=False,
192
- description="Maximum ephemeral storage (in GB) to "
193
- "be available for each replica.",
194
- default=8,
195
- example="2 (means 2 GB)")
196
-
197
-
198
84
  class NameSchema(Schema):
199
85
  """ Validated name string field.
200
86
  """
@@ -216,98 +102,6 @@ class NameSchema(Schema):
216
102
  return item
217
103
 
218
104
 
219
- class SermosImageConfigSchema(NameSchema):
220
- installCommand = fields.String(
221
- required=False,
222
- description="The pip install command to use when Sermos is "
223
- "responsible for building your image.",
224
- example="sermos-client-pkg[core,special_feature]")
225
- sourceSshUrl = fields.String(
226
- required=False,
227
- description="The source code ssh url to use when Sermos is "
228
- "responsible for building your image.",
229
- example="git@github.com:myorg/sermos-client.git")
230
- baseImage = fields.String(
231
- required=False,
232
- description="The Docker base image to use as the starting point when "
233
- "Sermos is responsible for building your image",
234
- example="rhoai/sermos:latest")
235
- repositoryUrl = fields.String(
236
- required=False,
237
- description="Deprecated - Use imageUri instead.")
238
- repositoryUser = fields.String(
239
- required=False,
240
- description="Deprecated - Use registryUser instead.",)
241
- repositoryPassword = fields.String(
242
- required=False,
243
- description="Deprecated - Use registryPassword instead.")
244
- imageUri = fields.String(
245
- required=False,
246
- description="The Docker image uri when using an image not built by "
247
- "Sermos. Tag is optional, if excluded, `latest` is used.",
248
- example="rhoai/custom-image ; rhoai/custom-image:v0.0.0")
249
- registryDomain = fields.String(
250
- required=False,
251
- description="Registry domain for using a pre-built image.",
252
- example="index.docker.io")
253
- registryUser = fields.String(
254
- required=False,
255
- description="Optional registry username if provided registryDomain"
256
- "is a private registry.",
257
- example="rhoai")
258
- registryPassword = fields.String(
259
- required=False,
260
- description="Optional registry password if provided registryDomain "
261
- "is a private registry. NOTE: Strongly recommended to use environment "
262
- "variable interpolation in your sermos.yaml file, do not commit "
263
- "unencrypted secrets to a git repository. "
264
- "e.g. repositoryPassword: ${DOCKER_REPOSITORY_PASSWORD}",
265
- example="abc123")
266
-
267
-
268
- class SermosSharedConfigSchema(Schema):
269
- """ Attributes shared across internal and external service types
270
- """
271
- command = fields.String(
272
- required=False,
273
- _required=True,
274
- description="Command to be run as container CMD.",
275
- example="gunicorn -b 0.0.0.0:5000 package.app:create_app()")
276
- port = fields.Integer(
277
- required=False,
278
- _required=True,
279
- description="Port (and targetPort) to direct traffic.",
280
- example=5000)
281
-
282
-
283
- class SermosExternalConfigSchema(SermosSharedConfigSchema):
284
- """ Attributes required for serviceType: external
285
-
286
- Note: Schema lists these are not required in order for this to be used
287
- as a mixin to SermosServiceConfigSchema. The validation is done
288
- programmatically based on serviceType.
289
- """
290
- serviceId = fields.String(
291
- required=False,
292
- _required=True,
293
- description="The serviceId provided by Sermos. Find in admin console.",
294
- example="dry-gorge-8018")
295
-
296
-
297
- class SermosInternalSchema(SermosSharedConfigSchema):
298
- """ Attributes required for serviceType: internal
299
-
300
- Note: Schema lists these are not required in order for this to be used
301
- as a mixin to SermosServiceConfigSchema. The validation is done
302
- programmatically based on serviceType.
303
- """
304
- protocol = fields.String(required=False,
305
- _required=True,
306
- description="Protocol to use.",
307
- example="TCP",
308
- validate=OneOf(['TCP', 'UDP']))
309
-
310
-
311
105
  class SermosRegisteredTaskDetailConfigSchema(Schema):
312
106
  handler = fields.String(
313
107
  required=True,
@@ -321,18 +115,9 @@ class SermosRegisteredTaskDetailConfigSchema(Schema):
321
115
 
322
116
 
323
117
  class SermosCeleryWorkerConfigSchema(Schema):
324
- """ Attributes required for serviceType: celery-worker
325
-
326
- Note: Schema lists these are not required in order for this to be used
327
- as a mixin to SermosServiceConfigSchema. The validation is done
328
- programmatically based on serviceType.
118
+ """ Attributes for a celery worker. This worker will run all of the
119
+ pipelines and scheduled tasks.
329
120
  """
330
- command = fields.String(
331
- required=False,
332
- _required=True,
333
- description="Command to be run as container CMD.",
334
- example="celery -A mypkg.celery.celery worker --queue my-queue")
335
-
336
121
  registeredTasks = fields.List(
337
122
  fields.Nested(SermosRegisteredTaskDetailConfigSchema, required=True),
338
123
  required=False,
@@ -341,47 +126,17 @@ class SermosCeleryWorkerConfigSchema(Schema):
341
126
  )
342
127
 
343
128
 
344
- # Mapping of serviceType keys to their respective schema
345
- service_types = {
346
- 'external': SermosExternalConfigSchema,
347
- 'internal': SermosInternalSchema,
348
- 'celery-worker': SermosCeleryWorkerConfigSchema
349
- }
350
-
351
-
352
- class SermosServiceConfigSchema(ExcludeUnknownSchema, ServiceRequestsSchema,
353
- EnvironmentVariablesSchema,
354
- SermosExternalConfigSchema,
355
- SermosInternalSchema,
129
+ class SermosServiceConfigSchema(ExcludeUnknownSchema,
356
130
  SermosCeleryWorkerConfigSchema, NameSchema):
357
- """ Base service config object definition for workers and internal/external
358
- services.
131
+ """ Base service config object definition for workers.
359
132
  """
360
- imageName = fields.String(
361
- required=True,
362
- description="Specify the name of the base image to use for this "
363
- "service.",
364
- example="custom-worker-name")
365
-
366
- serviceType = fields.String(required=True,
367
- description="Name of the worker.",
368
- example="useful_worker",
369
- validate=OneOf(service_types.keys()))
133
+ pass
370
134
 
371
135
 
372
- class SermosYamlSchema(ExcludeUnknownSchema, EnvironmentVariablesSchema):
136
+ class SermosYamlSchema(ExcludeUnknownSchema):
373
137
  """ The primary `sermos.yaml` file schema. This defines all available
374
138
  properties in a valid Sermos configuration file.
375
139
  """
376
-
377
- imageConfig = fields.List(fields.Nested(SermosImageConfigSchema,
378
- required=True),
379
- required=True,
380
- description="List of available base images. At "
381
- "least one image must be defined. The 'name' "
382
- "of the image is used in each service defined "
383
- "in `serviceConfig`")
384
-
385
140
  serviceConfig = fields.List(
386
141
  fields.Nested(SermosServiceConfigSchema,
387
142
  required=True,
@@ -414,17 +169,12 @@ class SermosYamlSchema(ExcludeUnknownSchema, EnvironmentVariablesSchema):
414
169
  Nested fields that are not required are not validated by Marshmallow
415
170
  by default. Do a single level down of validation for now.
416
171
 
417
- Each serviceType has attributes that are required but are listed
418
- as not required in the marshmallow schema. Validate here.
419
-
420
172
  imageConfig can provide *either* an install command for Sermos
421
173
  to use to build the image for customer *or* a Docker repository
422
174
  for Sermos to pull.
423
175
  """
424
176
  # Vaidate nested
425
177
  key_schema_pairs = (
426
- ('imageConfig', SermosImageConfigSchema),
427
- ('environmentVariables', EnvironmentVariableSchema),
428
178
  ('serviceConfig', SermosServiceConfigSchema),
429
179
  )
430
180
  for k_s in key_schema_pairs:
@@ -440,10 +190,8 @@ class SermosYamlSchema(ExcludeUnknownSchema, EnvironmentVariablesSchema):
440
190
  # required in order to use them as mixins for a generic service object,
441
191
  # however, they ARE required, so validate here using the custom
442
192
  # metadata property `_required`. Default to value of `required`.
443
- service_image_names = []
444
193
  for service in data.get('serviceConfig'):
445
- service_type = service['serviceType']
446
- schema = service_types[service_type]
194
+ schema = SermosCeleryWorkerConfigSchema
447
195
  for field in schema().fields:
448
196
  try:
449
197
  if schema().fields[field].metadata.get(
@@ -452,43 +200,7 @@ class SermosYamlSchema(ExcludeUnknownSchema, EnvironmentVariablesSchema):
452
200
  assert field in service
453
201
  except AssertionError:
454
202
  raise ValidationError(
455
- f"`{field}` missing in {service_type} definition.")
456
-
457
- service_image_names.append(service['imageName'])
458
-
459
- # Validate imageConfig
460
- image_names = []
461
- for image in data.get('imageConfig'):
462
- image_names.append(image['name'])
463
- try:
464
- if image.get('installCommand', None) is not None:
465
- assert image.get('repositoryUrl', None) is None
466
- if image.get('repositoryUrl', None) is not None:
467
- assert image.get('installCommand', None) is None
468
- except AssertionError:
469
- raise InvalidImageConfig(
470
- "Each imageConfig may have *either* an installCommand "
471
- "*or* a repositoryUrl but not both. Review "
472
- f"image `{image['name']}`")
473
-
474
- if image.get('installCommand', None) is not None:
475
- if image.get('sourceSshUrl') is None:
476
- raise InvalidImageConfig(
477
- "Each imageConfig must have a sourceSshUrl if "
478
- "installCommand is specified")
479
- if image.get('baseImage') is None:
480
- raise InvalidImageConfig(
481
- "Each imageConfig must have a baseImage if "
482
- "installCommand is specified")
483
-
484
- # Verify each imageName referenced in each service exists in imageConfig
485
- try:
486
- assert set(service_image_names).issubset(image_names)
487
- except AssertionError:
488
- raise InvalidImageConfig(
489
- "Mismatched imageName in at least one "
490
- f"service ({service_image_names}) compared to images available "
491
- f"in imageConfig ({image_names})")
203
+ f"`{field}` missing in worker definition.")
492
204
 
493
205
  # Validate unique pipeline ids
494
206
  if 'pipelines' in data:
@@ -612,11 +324,6 @@ def parse_config_file(sermos_yaml: str):
612
324
  .format(e.messages)
613
325
  logger.error(msg)
614
326
  raise InvalidSermosConfig(msg)
615
- except InvalidImageConfig as e:
616
- msg = "Invalid imageConfig configuration due to {}"\
617
- .format(e)
618
- logger.error(msg)
619
- raise InvalidImageConfig(msg)
620
327
  except Exception as e:
621
328
  msg = "Invalid Sermos configuration, likely due to invalid "\
622
329
  "YAML formatting ..."
@@ -680,8 +387,6 @@ def load_sermos_config(pkg_name: str = None,
680
387
  sermos_config = parse_config_file(sermos_yaml)
681
388
  except InvalidSermosConfig as e:
682
389
  raise
683
- except InvalidImageConfig as e:
684
- raise
685
390
  except FileNotFoundError as e:
686
391
  msg = "Sermos config file could not be found at path {} ...".format(
687
392
  sermos_config_path)