Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/sdl #203

Merged
merged 2 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions deploy-web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion deploy-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"dependencies": {
"@akashnetwork/akash-api": "^1.3.0",
"@akashnetwork/akashjs": "^0.9.0",
"@akashnetwork/akashjs": "^0.10.0",
"@auth0/nextjs-auth0": "^3.5.0",
"@cosmjs/encoding": "^0.29.5",
"@cosmjs/stargate": "^0.29.5",
Expand Down
8 changes: 3 additions & 5 deletions deploy-web/src/components/deployments/ManifestUpdate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type Props = {

export const ManifestUpdate: React.FunctionComponent<Props> = ({ deployment, leases, closeManifestEditor }) => {
const [parsingError, setParsingError] = useState<string | null>(null);
const [deploymentVersion, setDeploymentVersion] = useState(null);
const [deploymentVersion, setDeploymentVersion] = useState<string | null>(null);
const [editedManifest, setEditedManifest] = useState("");
const [isSendingManifest, setIsSendingManifest] = useState(false);
const [showOutsideDeploymentMessage, setShowOutsideDeploymentMessage] = useState(false);
Expand All @@ -54,7 +54,7 @@ export const ManifestUpdate: React.FunctionComponent<Props> = ({ deployment, lea
setEditedManifest(localDeploymentData?.manifest);

const yamlVersion = yaml.load(localDeploymentData?.manifest);
const version = await deploymentData.getManifestVersion(yamlVersion, true);
const version = await deploymentData.getManifestVersion(yamlVersion);

setDeploymentVersion(version);
} else {
Expand Down Expand Up @@ -113,9 +113,7 @@ export const ManifestUpdate: React.FunctionComponent<Props> = ({ deployment, lea

async function sendManifest(providerInfo: ApiProviderList, manifest: any) {
try {
const response = await sendManifestToProvider(providerInfo, manifest, deployment.dseq, localCert as LocalCert);

return response;
return await sendManifestToProvider(providerInfo, manifest, deployment.dseq, localCert as LocalCert);
} catch (err) {
enqueueSnackbar(<ManifestErrorSnackbar err={err} />, { variant: "error", autoHideDuration: null });
throw err;
Expand Down
3 changes: 1 addition & 2 deletions deploy-web/src/hooks/useSelectedNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import networkStore, { networks } from "@src/store/networkStore";
import { mainnetId } from "@src/utils/constants";

export const getSelectedNetwork = () => {
const selectedNetworkId = localStorage.getItem("selectedNetworkId") ?? mainnetId;
const selectedNetworkId = (typeof window !== "undefined" && localStorage.getItem("selectedNetworkId")) ?? mainnetId;
const selectedNetwork = networks.find(n => n.id === selectedNetworkId);

// return mainnet if selected network is not found
Expand All @@ -21,4 +21,3 @@ export const useSelectedNetwork = () => {

return selectedNetwork ?? networks[0];
};

29 changes: 11 additions & 18 deletions deploy-web/src/utils/deploymentData/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import { mainnetId, sandboxId, testnetId } from "../constants";
import * as v1beta3 from "./v1beta3";
import { mainnetId, testnetId, sandboxId } from "../constants";
import { getSelectedNetwork } from "@src/hooks/useSelectedNetwork";
import { NetworkId } from "@akashnetwork/akashjs/build/types/network";
export * from "./helpers";

export let deploymentData;
export let selectedNetworkId: string;
const NETWORK_SDL: Record<NetworkId, typeof v1beta3> = {
[mainnetId]: v1beta3,
[testnetId]: v1beta3,
[sandboxId]: v1beta3
};

export function initDeploymentData() {
selectedNetworkId = localStorage.getItem("selectedNetworkId") || mainnetId;

switch (selectedNetworkId) {
case mainnetId:
case testnetId:
case sandboxId:
deploymentData = v1beta3;
break;

default:
deploymentData = v1beta3;
break;
}
}
export let selectedNetwork = getSelectedNetwork();
export let selectedNetworkId = selectedNetwork.id;
export const deploymentData = NETWORK_SDL[selectedNetworkId];
201 changes: 37 additions & 164 deletions deploy-web/src/utils/deploymentData/v1beta3.ts
Original file line number Diff line number Diff line change
@@ -1,144 +1,20 @@
import { CustomValidationError, DeploymentGroups, getCurrentHeight, getSdl, Manifest, ManifestVersion, parseSizeStr } from "./helpers";
import { defaultInitialDeposit } from "../constants";
import { stringToBoolean } from "../stringUtils";
import path from "path";
import yaml from "js-yaml";
import { getSelectedNetwork } from "@src/hooks/useSelectedNetwork";
import { NetworkId } from "@akashnetwork/akashjs/build/types/network";

export const endpointNameValidationRegex = /^[a-z]+[-_\da-z]+$/;

function validate(yamlStr: string, yamlJson, networkId: NetworkId) {
try {
// TODO: use result of this in client code instead of just using validation
getSdl(yamlJson, "beta3", networkId);
} catch (e) {
const error = new CustomValidationError(e.message);
error.stack = e.stack;
throw error;
}

Object.keys(yamlJson.services).forEach(svcName => {
const svc = yamlJson.services[svcName];
const depl = yamlJson.deployment[svcName];

Object.keys(depl).forEach(placementName => {
const svcdepl = depl[placementName];
const compute = yamlJson.profiles.compute[svcdepl.profile];

// STORAGE VALIDATION
const storages = compute.resources.storage.map ? compute.resources.storage : [compute.resources.storage];
const volumes = {};
const attr = {};
const mounts = {};

storages?.forEach(storage => {
const name = storage.name || "default";
volumes[name] = {
name,
quantity: { val: parseSizeStr(storage.size) },
attributes:
storage.attributes &&
Object.keys(storage.attributes)
.sort()
.map(key => {
const value = storage.attributes[key].toString();
// add the storage attributes
attr[key] = value;

return {
key,
value
};
})
};
});

if (svc.params) {
(Object.keys(svc.params?.storage || {}) || []).forEach(name => {
const params = svc.params.storage[name];
if (!volumes[name]) {
throw new CustomValidationError(`Service "${svcName}" references to no-existing compute volume names "${name}".`);
}

if (!path.isAbsolute(params.mount)) {
throw new CustomValidationError(`Invalid value for "service.${svcName}.params.${name}.mount" parameter. expected absolute path.`);
}

// merge the service params attributes
attr["mount"] = params.mount;
attr["readOnly"] = params.readOnly || false;
const mount = attr["mount"];
const vlname = mounts[mount];

if (vlname) {
if (!mount) {
throw new CustomValidationError("Multiple root ephemeral storages are not allowed");
}

throw new CustomValidationError(`Mount ${mount} already in use by volume ${vlname}.`);
}

mounts[mount] = name;
});
}

(Object.keys(volumes) || []).forEach(volume => {
volumes[volume].attributes?.forEach(nd => {
attr[nd.key] = nd.value;
});

const persistent = stringToBoolean(attr["persistent"]);

if (persistent && !attr["mount"]) {
throw new CustomValidationError(
`compute.storage.${volume} has persistent=true which requires service.${svcName}.params.storage.${volume} to have mount.`
);
}
});

// GPU VALIDATION
const gpu = compute.resources.gpu;

if (gpu) {
if (gpu.units === 0 && gpu.attributes) {
throw new CustomValidationError(`Invalid GPU configuration for "${svcName}".`);
}

if (gpu.units > 0 && !gpu.attributes) {
throw new CustomValidationError(`Invalid GPU configuration for "${svcName}". Missing attributes with vendor and nvidia.`);
}

if (gpu.units > 0 && !("vendor" in gpu.attributes)) {
throw new CustomValidationError(`Invalid GPU configuration for "${svcName}". Missing vendor with nvidia in attributes.`);
}

if (gpu.units > 0 && !("nvidia" in gpu.attributes.vendor)) {
throw new CustomValidationError(`Invalid GPU configuration for "${svcName}". Missing nvidia in attributes.vendor.`);
}
import { CustomValidationError, getCurrentHeight, getSdl, Manifest, ManifestVersion, parseSizeStr } from "./helpers";
import { defaultInitialDeposit } from "../constants";

if (gpu.units > 0 && !!gpu.attributes.vendor.nvidia && !Array.isArray(gpu.attributes.vendor.nvidia)) {
throw new CustomValidationError(`Invalid GPU configuration for "${svcName}". Nvidia must be an array of GPU models with optional ram.`);
}
}
});
});
}
export const endpointNameValidationRegex = /^[a-z]+[-_\da-z]+$/;

export function getManifest(yamlJson, asString: boolean) {
const network = getSelectedNetwork();
return Manifest(yamlJson, "beta3", network.id, asString);
}

export async function getManifestVersion(yamlJson, asString = false) {
export async function getManifestVersion<T extends boolean>(yamlJson) {
const network = getSelectedNetwork();
const version = await ManifestVersion(yamlJson, "beta3", network.id);

if (asString) {
return Buffer.from(version).toString("base64");
} else {
return version;
}
return Buffer.from(version).toString("base64");
}

const getDenomFromSdl = (groups: any[]): string => {
Expand All @@ -151,43 +27,40 @@ const getDenomFromSdl = (groups: any[]): string => {
export async function NewDeploymentData(
apiEndpoint: string,
yamlStr: string,
dseq: string,
dseq: string | null,
fromAddress: string,
deposit = defaultInitialDeposit,
depositorAddress = null
depositorAddress: string | null = null
) {
const { id: networkId } = getSelectedNetwork();
const yamlJson = yaml.load(yamlStr) as any;

// Validate the integrity of the yaml
validate(yamlStr, yamlJson, networkId);

const groups = DeploymentGroups(yamlJson, "beta3", networkId);
const mani = Manifest(yamlJson, "beta3", networkId);
const denom = getDenomFromSdl(groups);
const version = await ManifestVersion(yamlJson, "beta3", networkId);
const id = {
owner: fromAddress,
dseq: dseq
};
const _deposit = {
denom,
amount: deposit.toString()
};

if (!id.dseq) {
id.dseq = (await getCurrentHeight(apiEndpoint)).toString();
try {
const { id: networkId } = getSelectedNetwork();
const sdl = getSdl(yamlStr, "beta3", networkId);
const groups = sdl.groups();
const mani = sdl.manifest();
const denom = getDenomFromSdl(groups);
const version = await sdl.manifestVersion();
const _deposit = {
denom,
amount: deposit.toString()
};

return {
sdl: sdl.data,
manifest: mani,
groups: groups,
deploymentId: {
owner: fromAddress,
dseq: dseq || (await getCurrentHeight(apiEndpoint)).toString()
},
orderId: [],
leaseId: [],
version,
deposit: _deposit,
depositor: depositorAddress || fromAddress
};
} catch (e) {
const error = new CustomValidationError(e.message);
error.stack = e.stack;
throw error;
}

return {
sdl: yamlJson,
manifest: mani,
groups: groups,
deploymentId: id,
orderId: [],
leaseId: [],
version,
deposit: _deposit,
depositor: depositorAddress || fromAddress
};
}
7 changes: 2 additions & 5 deletions deploy-web/src/utils/deploymentLocalDataUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,15 @@ export type LocalDeploymentData = {
manifestVersion?: Uint8Array;
};

export function getDeploymentLocalData(dseq: string | number) {
export function getDeploymentLocalData(dseq: string | number): LocalDeploymentData | null {
const selectedNetworkId = localStorage.getItem("selectedNetworkId");
const selectedWallet = getSelectedStorageWallet();

if (!selectedWallet) return null;

const dataStr = localStorage.getItem(`${selectedNetworkId}/${selectedWallet.address}/deployments/${dseq}.data`);
if (!dataStr) return null;

const parsedData = JSON.parse(dataStr) as LocalDeploymentData;

return parsedData;
return dataStr ? JSON.parse(dataStr) : null;
}

export function saveDeploymentManifestAndName(dseq: string, manifest: string, version: Uint8Array, address: string, name: string) {
Expand Down
2 changes: 0 additions & 2 deletions deploy-web/src/utils/init.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { setNetworkVersion } from "./constants";
import { initDeploymentData } from "./deploymentData";
import { initProtoTypes } from "./proto";
import { setMessageTypes } from "./TransactionMessageData";

export const initAppTypes = () => {
setNetworkVersion();
initProtoTypes();
setMessageTypes();
initDeploymentData();
};
Loading