pull images.

This commit is contained in:
Miroslav Šedivý
2021-12-11 22:09:21 +01:00
parent 30807ae903
commit 64a3a8898b
11 changed files with 839 additions and 0 deletions
+337
View File
@@ -100,6 +100,118 @@ export interface BrowserPolicyExtension {
*/
'url'?: string;
}
/**
*
* @export
* @interface PullLayer
*/
export interface PullLayer {
/**
*
* @type {string}
* @memberof PullLayer
*/
'status'?: string;
/**
*
* @type {PullLayerProgressDetail}
* @memberof PullLayer
*/
'progressDetail'?: PullLayerProgressDetail;
/**
*
* @type {string}
* @memberof PullLayer
*/
'progress'?: string;
/**
*
* @type {string}
* @memberof PullLayer
*/
'id'?: string;
}
/**
*
* @export
* @interface PullLayerProgressDetail
*/
export interface PullLayerProgressDetail {
/**
*
* @type {number}
* @memberof PullLayerProgressDetail
*/
'current'?: number;
/**
*
* @type {number}
* @memberof PullLayerProgressDetail
*/
'total'?: number;
}
/**
*
* @export
* @interface PullStart
*/
export interface PullStart {
/**
*
* @type {string}
* @memberof PullStart
*/
'neko_image'?: string;
/**
*
* @type {string}
* @memberof PullStart
*/
'registry_user'?: string;
/**
*
* @type {string}
* @memberof PullStart
*/
'registry_pass'?: string;
}
/**
*
* @export
* @interface PullStatus
*/
export interface PullStatus {
/**
*
* @type {boolean}
* @memberof PullStatus
*/
'active'?: boolean;
/**
*
* @type {string}
* @memberof PullStatus
*/
'started'?: string;
/**
*
* @type {{ [key: string]: PullLayer; }}
* @memberof PullStatus
*/
'layers'?: { [key: string]: PullLayer; };
/**
*
* @type {Array<string>}
* @memberof PullStatus
*/
'status'?: Array<string>;
/**
*
* @type {string}
* @memberof PullStatus
*/
'finished'?: string;
}
/**
*
* @export
@@ -577,6 +689,231 @@ export class ConfigApi extends BaseAPI {
}
/**
* DefaultApi - axios parameter creator
* @export
*/
export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
*
* @summary Start new pull
* @param {PullStart} [pullStart]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
pullStart: async (pullStart?: PullStart, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/pull`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
localVarHeaderParameter['Content-Type'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(pullStart, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary Get pull status
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
pullStatus: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/pull`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary Stop existing pull in progress
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
pullStop: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/pull`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
}
};
/**
* DefaultApi - functional programming interface
* @export
*/
export const DefaultApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration)
return {
/**
*
* @summary Start new pull
* @param {PullStart} [pullStart]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async pullStart(pullStart?: PullStart, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PullStatus>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.pullStart(pullStart, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @summary Get pull status
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async pullStatus(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PullStatus>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.pullStatus(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @summary Stop existing pull in progress
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async pullStop(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.pullStop(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
}
};
/**
* DefaultApi - factory interface
* @export
*/
export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
const localVarFp = DefaultApiFp(configuration)
return {
/**
*
* @summary Start new pull
* @param {PullStart} [pullStart]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
pullStart(pullStart?: PullStart, options?: any): AxiosPromise<PullStatus> {
return localVarFp.pullStart(pullStart, options).then((request) => request(axios, basePath));
},
/**
*
* @summary Get pull status
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
pullStatus(options?: any): AxiosPromise<PullStatus> {
return localVarFp.pullStatus(options).then((request) => request(axios, basePath));
},
/**
*
* @summary Stop existing pull in progress
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
pullStop(options?: any): AxiosPromise<void> {
return localVarFp.pullStop(options).then((request) => request(axios, basePath));
},
};
};
/**
* DefaultApi - object-oriented interface
* @export
* @class DefaultApi
* @extends {BaseAPI}
*/
export class DefaultApi extends BaseAPI {
/**
*
* @summary Start new pull
* @param {PullStart} [pullStart]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof DefaultApi
*/
public pullStart(pullStart?: PullStart, options?: AxiosRequestConfig) {
return DefaultApiFp(this.configuration).pullStart(pullStart, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary Get pull status
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof DefaultApi
*/
public pullStatus(options?: AxiosRequestConfig) {
return DefaultApiFp(this.configuration).pullStatus(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary Stop existing pull in progress
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof DefaultApi
*/
public pullStop(options?: AxiosRequestConfig) {
return DefaultApiFp(this.configuration).pullStop(options).then((request) => request(this.axios, this.basePath));
}
}
/**
* RoomsApi - axios parameter creator
* @export
+142
View File
@@ -0,0 +1,142 @@
<template>
<span>
<v-btn
@click="dialog = true"
:loading="loading"
color="info"
dark
>
<v-icon class="mr-2" color="white">mdi-cloud-download-outline</v-icon> Pull neko images
</v-btn>
<v-dialog v-model="dialog" max-width="920px">
<v-card>
<v-card-title class="headline">
Pull neko images
</v-card-title>
<v-card-text>
<template v-if="status.layers.length > 0">
<pre v-for="layer in status.layers" :key="layer.id">{{ layer.id }} {{ layer.progress && layer.progress + ' ' }}{{ layer.status }}</pre>
<br />
</template>
<template v-if="status.status.length > 0">
<pre v-for="text in status.status" :key="text">{{ text }}</pre>
</template>
<pre v-else>Preparing docker image pull</pre>
</v-card-text>
<v-card-actions>
<template v-if="!status.active">
<v-select
v-model="nekoImage"
:items="nekoImages"
dense
outlined
hide-details
label="Neko image"
></v-select>
<v-btn color="green" class="ml-2" :loading="loading" @click="Start">
Start
</v-btn>
</template>
<v-spacer></v-spacer>
<v-btn v-if="status.active" color="red" text :loading="loading" @click="Stop">
Stop
</v-btn>
<v-btn v-else color="grey" text @click="dialog = false">
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</span>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
@Component({
components: {}
})
export default class PUll extends Vue {
private dialog = false
private loading = false
private nekoImage = ''
get status() {
return this.$store.state.pullStatus
}
get nekoImages() {
return this.$store.state.roomsConfig.neko_images
}
async Start() {
this.loading = true
try {
await this.$store.dispatch('PULL_START', this.nekoImage)
} catch(e) {
if (e.response) {
this.$swal({
title: 'Server error',
text: e.response.data,
icon: 'error',
})
} else {
this.$swal({
title: 'Network error',
text: String(e),
icon: 'error',
})
}
} finally {
this.loading = false
}
}
async Stop() {
this.loading = true
try {
await this.$store.dispatch('PULL_STOP')
} catch(e) {
if (e.response) {
this.$swal({
title: 'Server error',
text: e.response.data,
icon: 'error',
})
} else {
this.$swal({
title: 'Network error',
text: String(e),
icon: 'error',
})
}
} finally {
this.loading = false
this.dialog = false
}
}
private interval!: number
async mounted() {
await this.$store.dispatch('PULL_STATUS')
this.interval = window.setInterval(async () => {
if (!this.status.active) return
try {
await this.$store.dispatch('PULL_STATUS')
} catch(e) {
console.error(e)
}
}, 1000)
}
beforeDestroy() {
window.clearInterval(this.interval)
}
}
</script>
+23
View File
@@ -9,6 +9,8 @@ import {
RoomSettings,
RoomStats,
RoomsApi,
DefaultApi,
PullStatus,
} from '@/api/index'
import { state, State } from './state'
@@ -21,6 +23,7 @@ const configuration = new Configuration({
const configApi = new ConfigApi(configuration)
const roomsApi = new RoomsApi(configuration)
const defaultApi = new DefaultApi(configuration)
export default new Vuex.Store({
state,
@@ -55,6 +58,9 @@ export default new Vuex.Store({
const roomEntries = state.rooms.filter(({ id }) => id != roomId)
Vue.set(state, 'rooms', roomEntries)
},
PULL_STATUS(state: State, pullStatus: PullStatus) {
Vue.set(state, 'pullStatus', pullStatus)
},
},
actions: {
async ROOMS_CONFIG({ commit }: ActionContext<State, State>) {
@@ -112,6 +118,23 @@ export default new Vuex.Store({
commit('ROOMS_PUT', res.data)
return res.data
},
async PULL_START({ commit }: ActionContext<State, State>, nekoImage: string) {
const res = await defaultApi.pullStart({
// eslint-disable-next-line
neko_image: nekoImage,
})
commit('PULL_STATUS', res.data)
return res.data
},
async PULL_STATUS({ commit }: ActionContext<State, State>) {
const res = await defaultApi.pullStatus()
commit('PULL_STATUS', res.data)
},
async PULL_STOP() {
const res = await defaultApi.pullStop()
return res.data
},
},
modules: {
}
+8
View File
@@ -5,6 +5,7 @@ import {
BrowserPolicyContent,
BrowserPolicyTypeEnum,
BrowserPolicyExtension,
PullStatus,
} from '@/api/index'
export interface BrowserPolicyConfig {
@@ -208,6 +209,13 @@ export const state = {
// eslint-disable-next-line
persistent_data: false,
} as BrowserPolicyContent,
//
// default
//
pullStatus: {
active: false,
} as PullStatus
}
export type State = typeof state
+6
View File
@@ -58,6 +58,10 @@
</v-row>
<RoomsList :loading="loading" />
<div class="mt-5 text-center">
<Pull />
</div>
</v-container>
</template>
@@ -66,6 +70,7 @@ import { Component, Vue, Watch } from 'vue-property-decorator'
import RoomsList from '@/components/RoomsList.vue'
import RoomsQuick from '@/components/RoomsQuick.vue'
import RoomsCreate from '@/components/RoomsCreate.vue'
import Pull from '@/components/Pull.vue'
import { RoomEntry } from '@/api/index'
@Component({
@@ -73,6 +78,7 @@ import { RoomEntry } from '@/api/index'
RoomsList,
RoomsQuick,
RoomsCreate,
Pull,
}
})
export default class Home extends Vue {