forked from mlrun/mlrun
/
marketplace.py
128 lines (100 loc) · 4.14 KB
/
marketplace.py
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
# Copyright 2018 Iguazio
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from datetime import datetime, timezone
from typing import List, Optional
from pydantic import BaseModel, Extra, Field
import mlrun.errors
from mlrun.api.schemas.object import ObjectKind, ObjectSpec, ObjectStatus
from mlrun.api.utils.helpers import StrEnum
from mlrun.config import config
# Defining a different base class (not ObjectMetadata), as there's no project and it differs enough to
# justify a new class
class MarketplaceObjectMetadata(BaseModel):
name: str
description: str = ""
labels: Optional[dict]
updated: Optional[datetime]
created: Optional[datetime]
class Config:
extra = Extra.allow
# Currently only functions are supported. Will add more in the future.
class MarketplaceSourceType(StrEnum):
functions = "functions"
# Sources-related objects
class MarketplaceSourceSpec(ObjectSpec):
path: str # URL to base directory, should include schema (s3://, etc...)
channel: str
credentials: Optional[dict] = None
class MarketplaceSource(BaseModel):
kind: ObjectKind = Field(ObjectKind.marketplace_source, const=True)
metadata: MarketplaceObjectMetadata
spec: MarketplaceSourceSpec
status: Optional[ObjectStatus] = ObjectStatus(state="created")
def get_full_uri(self, relative_path):
return "{base}/{channel}/{relative_path}".format(
base=self.spec.path, channel=self.spec.channel, relative_path=relative_path
)
def get_catalog_uri(self):
return self.get_full_uri(config.marketplace.catalog_filename)
@classmethod
def generate_default_source(cls):
if not config.marketplace.default_source.create:
return None
now = datetime.now(timezone.utc)
hub_metadata = MarketplaceObjectMetadata(
name=config.marketplace.default_source.name,
description=config.marketplace.default_source.description,
created=now,
updated=now,
)
return cls(
metadata=hub_metadata,
spec=MarketplaceSourceSpec(
path=config.marketplace.default_source.url,
channel=config.marketplace.default_source.channel,
),
status=ObjectStatus(state="created"),
)
last_source_index = -1
class IndexedMarketplaceSource(BaseModel):
index: int = last_source_index # Default last. Otherwise must be > 0
source: MarketplaceSource
# Item-related objects
class MarketplaceItemMetadata(MarketplaceObjectMetadata):
source: MarketplaceSourceType = Field(MarketplaceSourceType.functions, const=True)
channel: str
version: str
tag: Optional[str]
def get_relative_path(self) -> str:
if self.source == MarketplaceSourceType.functions:
# This is needed since the marketplace deployment script modifies the paths to use _ instead of -.
modified_name = self.name.replace("-", "_")
# Prefer using the tag if exists. Otherwise use version.
version = self.tag or self.version
return f"{self.source.value}/{self.channel}/{modified_name}/{version}/"
else:
raise mlrun.errors.MLRunInvalidArgumentError(
f"Bad source for marketplace item - {self.source}"
)
class MarketplaceItemSpec(ObjectSpec):
item_uri: str
class MarketplaceItem(BaseModel):
kind: ObjectKind = Field(ObjectKind.marketplace_item, const=True)
metadata: MarketplaceItemMetadata
spec: MarketplaceItemSpec
status: ObjectStatus
class MarketplaceCatalog(BaseModel):
kind: ObjectKind = Field(ObjectKind.marketplace_catalog, const=True)
catalog: List[MarketplaceItem]