1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-07-10 05:25:41 +00:00

Merge pull request #3 from retspen/master

add
This commit is contained in:
aiminick 2021-04-12 02:10:40 +08:00 committed by GitHub
commit cd798eb9b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
94 changed files with 1874 additions and 1697 deletions

View file

@ -22,7 +22,7 @@
How to update <code>gstfsd</code> daemon on hypervisor:
```bash
wget -O - https://clck.ru/9VMRH | sudo tee -a /usr/local/bin/gstfsd
wget -O - https://bit.ly/2NAaWXG | sudo tee -a /usr/local/bin/gstfsd
sudo service supervisor restart
```
@ -86,7 +86,7 @@ sudo service supervisor restart
Setup libvirt and KVM on server
```bash
wget -O - https://clck.ru/9V9fH | sudo sh
wget -O - https://bit.ly/36baWUu | sudo sh
```
Done!!

View file

@ -4,8 +4,10 @@ from instances.models import Instance
def refresh_instance_database(compute):
domains = compute.proxy.wvm.listAllDomains()
domain_names = [d.name() for d in domains]
domain_uuids = [d.UUIDString() for d in domains]
# Delete instances that're not on host from DB
Instance.objects.filter(compute=compute).exclude(name__in=domain_names).delete()
Instance.objects.filter(compute=compute).exclude(uuid__in=domain_uuids).delete()
# Create instances that're on host but not in DB
names = Instance.objects.filter(compute=compute).values_list('name', flat=True)
for domain in domains:

View file

@ -1,14 +1,13 @@
Django==2.2.17
Django==2.2.19
django-bootstrap4==2.3.1
django-icons==2.2.0
django-icons==2.2.1
django-login-required-middleware==0.5.0
django-otp==1.0.2
django-qr-code==1.3.1
gunicorn==20.0.4
importlib-metadata==2.0.0
libsass==0.20.1
libvirt-python==6.9.0
lxml==4.6.1
libvirt-python==7.1.0
lxml==4.6.3
qrcode==6.1
rwlock==0.0.7
websockify==0.9.0

View file

@ -1,5 +1,5 @@
[program:gstfsd]
command=/srv/webvirtcloud/venv/bin/python3 /usr/local/bin/gstfsd
command=/usr/bin/python3 /usr/local/bin/gstfsd
directory=/usr/local/bin
user=root
autostart=true

View file

@ -45,7 +45,7 @@ echowarn() {
# DESCRIPTION: Echo debug information to stdout.
#-------------------------------------------------------------------------------
echodebug() {
if [ "$_ECHO_DEBUG" -eq "$BS_TRUE" ]; then
if [ $_ECHO_DEBUG -eq $BS_TRUE ]; then
printf "${BC} * DEBUG${EC}: %s\n" "$@";
fi
}
@ -342,7 +342,7 @@ __check_end_of_life_versions() {
;;
centos)
# CentOS versions lower than 5 are no longer supported
# CentOS versions lower than 6 are no longer supported
if { [ "$DISTRO_MAJOR_VERSION" -eq 6 ] && [ "$DISTRO_MINOR_VERSION" -lt 3 ]; } || [ "$DISTRO_MAJOR_VERSION" -lt 5 ]; then
echoerror "End of life distributions are not supported."
echoerror "Please consider upgrading to the next stable. See:"
@ -374,13 +374,18 @@ __check_end_of_life_versions
# CentOS Install Functions
#
install_centos() {
if [ "$DISTRO_MAJOR_VERSION" -ge 6 ]; then
yum -y install qemu-kvm libvirt bridge-utils python-libguestfs libguestfs-tools supervisor cyrus-sasl-md5 epel-release || return 1
yum -y install epel-release || return 1
if [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then
yum -y install qemu-kvm libvirt bridge-utils python-libguestfs libguestfs-tools supervisor cyrus-sasl-md5 || return 1
else
yum -y install qemu-kvm libvirt python3-libguestfs libguestfs-tools cyrus-sasl-md5 supervisor || return 1
fi
return 0
}
install_centos_post() {
if [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then
if [ -f /etc/sysconfig/libvirtd ]; then
sed -i 's/#LIBVIRTD_ARGS/LIBVIRTD_ARGS/g' /etc/sysconfig/libvirtd
else
@ -395,6 +400,7 @@ install_centos_post() {
echoerror "/etc/libvirt/libvirtd.conf not found. Exiting..."
exit 1
fi
fi
if [ -f /etc/libvirt/qemu.conf ]; then
sed -i 's/#[ ]*vnc_listen.*/vnc_listen = "0.0.0.0"/g' /etc/libvirt/qemu.conf
sed -i 's/#[ ]*spice_listen.*/spice_listen = "0.0.0.0"/g' /etc/libvirt/qemu.conf
@ -440,14 +446,24 @@ daemons_running_centos() {
service libvirt-guests stop > /dev/null 2>&1
service libvirt-guests start
fi
if [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then
if [ -f /usr/lib/systemd/system/libvirtd.service ]; then
systemctl stop libvirtd.service > /dev/null 2>&1
systemctl start libvirtd.service
fi
else
if [ -f /usr/lib/systemd/system/libvirtd-tcp.socket ]; then
systemctl stop libvirtd-tcp.socket > /dev/null 2>&1
systemctl start libvirtd-tcp.socket
fi
fi
if [ -f /usr/lib/systemd/system/libvirt-guests.service ]; then
systemctl stop libvirt-guests.service > /dev/null 2>&1
systemctl start libvirt-guests.service
fi
if [ -f /etc/init.d/supervisord ]; then
service supervisord stop > /dev/null 2>&1
service supervisord start
@ -599,7 +615,6 @@ install_ubuntu() {
apt install -y qemu-kvm libvirt-bin bridge-utils virt-manager sasl2-bin python3-guestfs supervisor || return 1
fi
return 0
}

View file

@ -1,7 +1,7 @@
-r ../conf/requirements.txt
coverage==5.3
django-debug-toolbar==3.1.1
pycodestyle==2.6.0
pyflakes==2.2.0
pylint==2.6.0
yapf==0.30.0
coverage==5.5
django-debug-toolbar==3.2
pycodestyle==2.7.0
pyflakes==2.3.1
pylint==2.7.2
yapf==0.31.0

View file

@ -10,14 +10,12 @@
}
.breadcrumb-item {
display: flex;
// The separator between breadcrumbs (by default, a forward-slash: "/")
+ .breadcrumb-item {
padding-left: $breadcrumb-item-padding;
&::before {
display: inline-block; // Suppress underlining of the separator in modern browsers
float: left; // Suppress inline spacings and underlining of the separator
padding-right: $breadcrumb-item-padding;
color: $breadcrumb-divider-color;
content: escape-svg($breadcrumb-divider);

View file

@ -127,7 +127,7 @@
display: inline-block;
width: $carousel-control-icon-width;
height: $carousel-control-icon-width;
background: no-repeat 50% / 100% 100%;
background: 50% / 100% 100% no-repeat;
}
.carousel-control-prev-icon {
background-image: escape-svg($carousel-control-prev-icon-bg);

View file

@ -104,7 +104,7 @@
width: $custom-control-indicator-size;
height: $custom-control-indicator-size;
content: "";
background: no-repeat 50% / #{$custom-control-indicator-bg-size};
background: 50% / #{$custom-control-indicator-bg-size} no-repeat;
}
}
@ -315,6 +315,7 @@
width: 100%;
height: $custom-file-height;
margin: 0;
overflow: hidden;
opacity: 0;
&:focus ~ .custom-file-label {
@ -347,6 +348,7 @@
z-index: 1;
height: $custom-file-height;
padding: $custom-file-padding-y $custom-file-padding-x;
overflow: hidden;
font-family: $custom-file-font-family;
font-weight: $custom-file-font-weight;
line-height: $custom-file-line-height;
@ -388,7 +390,7 @@
appearance: none;
&:focus {
outline: none;
outline: 0;
// Pseudo-elements must be split across multiple rulesets to have an effect.
// No box-shadow() mixin for focus accessibility.

View file

@ -100,7 +100,7 @@
}
}
// When enabled Popper.js, reset basic dropdown position
// When Popper is enabled, reset the basic dropdown position
// stylelint-disable-next-line no-duplicate-selectors
.dropdown-menu {
&[x-placement^="top"],

View file

@ -42,7 +42,6 @@
> .form-control,
> .custom-select {
&:not(:last-child) { @include border-right-radius(0); }
&:not(:first-child) { @include border-left-radius(0); }
}
@ -53,9 +52,24 @@
align-items: center;
&:not(:last-child) .custom-file-label,
&:not(:last-child) .custom-file-label::after { @include border-right-radius(0); }
&:not(:first-child) .custom-file-label { @include border-left-radius(0); }
}
&:not(.has-validation) {
> .form-control:not(:last-child),
> .custom-select:not(:last-child),
> .custom-file:not(:last-child) .custom-file-label::after {
@include border-right-radius(0);
}
}
&.has-validation {
> .form-control:nth-last-child(n + 3),
> .custom-select:nth-last-child(n + 3),
> .custom-file:nth-last-child(n + 3) .custom-file-label::after {
@include border-right-radius(0);
}
}
}
@ -175,8 +189,10 @@
.input-group > .input-group-prepend > .btn,
.input-group > .input-group-prepend > .input-group-text,
.input-group > .input-group-append:not(:last-child) > .btn,
.input-group > .input-group-append:not(:last-child) > .input-group-text,
.input-group:not(.has-validation) > .input-group-append:not(:last-child) > .btn,
.input-group:not(.has-validation) > .input-group-append:not(:last-child) > .input-group-text,
.input-group.has-validation > .input-group-append:nth-last-child(n + 3) > .btn,
.input-group.has-validation > .input-group-append:nth-last-child(n + 3) > .input-group-text,
.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),
.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) {
@include border-right-radius(0);

View file

@ -35,11 +35,8 @@
.nav-tabs {
border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color;
.nav-item {
margin-bottom: -$nav-tabs-border-width;
}
.nav-link {
margin-bottom: -$nav-tabs-border-width;
border: $nav-tabs-border-width solid transparent;
@include border-top-radius($nav-tabs-border-radius);

View file

@ -136,8 +136,12 @@
height: 1.5em;
vertical-align: middle;
content: "";
background: no-repeat center center;
background-size: 100% 100%;
background: 50% / 100% 100% no-repeat;
}
.navbar-nav-scroll {
max-height: $navbar-nav-scroll-max-height;
overflow-y: auto;
}
// Generate series of `.navbar-expand-*` responsive classes for configuring
@ -199,6 +203,10 @@
}
}
.navbar-nav-scroll {
overflow: visible;
}
.navbar-collapse {
display: flex !important; // stylelint-disable-line declaration-no-important

View file

@ -66,9 +66,9 @@
//
.pagination-lg {
@include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $line-height-lg, $border-radius-lg);
@include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $line-height-lg, $pagination-border-radius-lg);
}
.pagination-sm {
@include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $line-height-sm, $border-radius-sm);
@include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $line-height-sm, $pagination-border-radius-sm);
}

View file

@ -36,7 +36,7 @@
@if $enable-transitions {
.progress-bar-animated {
animation: progress-bar-stripes $progress-bar-animation-timing;
animation: $progress-bar-animation-timing progress-bar-stripes;
@if $enable-prefers-reduced-motion-media-query {
@media (prefers-reduced-motion: reduce) {

View file

@ -1,4 +1,4 @@
// stylelint-disable at-rule-no-vendor-prefix, declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix
// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix
// Reboot
//
@ -307,13 +307,13 @@ button {
border-radius: 0;
}
// Work around a Firefox/IE bug where the transparent `button` background
// results in a loss of the default `button` focus styles.
//
// Credit: https://github.com/suitcss/base/
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
// Explicitly remove focus outline in Chromium when it shouldn't be
// visible (e.g. as result of mouse click or touch tap). It already
// should be doing this automatically, but seems to currently be
// confused and applies its very visible two-tone outline anyway.
button:focus:not(:focus-visible) {
outline: 0;
}
input,

View file

@ -1,4 +1,3 @@
// Do not forget to update getting-started/theming.md!
:root {
// Custom variable values only support SassScript inside `#{}`.
@each $color, $value in $colors {

View file

@ -15,7 +15,7 @@
border-right-color: transparent;
// stylelint-disable-next-line property-disallowed-list
border-radius: 50%;
animation: spinner-border .75s linear infinite;
animation: .75s linear infinite spinner-border;
}
.spinner-border-sm {
@ -47,10 +47,19 @@
// stylelint-disable-next-line property-disallowed-list
border-radius: 50%;
opacity: 0;
animation: spinner-grow .75s linear infinite;
animation: .75s linear infinite spinner-grow;
}
.spinner-grow-sm {
width: $spinner-width-sm;
height: $spinner-height-sm;
}
@if $enable-prefers-reduced-motion-media-query {
@media (prefers-reduced-motion: reduce) {
.spinner-border,
.spinner-grow {
animation-duration: 1.5s;
}
}
}

View file

@ -1,4 +1,4 @@
// stylelint-disable declaration-no-important, selector-list-comma-newline-after
// stylelint-disable selector-list-comma-newline-after
//
// Headings

View file

@ -274,7 +274,7 @@ $embed-responsive-aspect-ratios: join(
// Font, line-height, and color for body text, headings, and more.
// stylelint-disable value-keyword-case
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default;
$font-family-base: $font-family-sans-serif !default;
// stylelint-enable value-keyword-case
@ -583,7 +583,7 @@ $custom-select-disabled-bg: $gray-200 !default;
$custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions
$custom-select-indicator-color: $gray-800 !default;
$custom-select-indicator: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'><path fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/></svg>") !default;
$custom-select-background: escape-svg($custom-select-indicator) no-repeat right $custom-select-padding-x center / $custom-select-bg-size !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon)
$custom-select-background: escape-svg($custom-select-indicator) right $custom-select-padding-x center / $custom-select-bg-size no-repeat !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon)
$custom-select-feedback-icon-padding-right: add(1em * .75, (2 * $custom-select-padding-y * .75) + $custom-select-padding-x + $custom-select-indicator-padding) !default;
$custom-select-feedback-icon-position: center right ($custom-select-padding-x + $custom-select-indicator-padding) !default;
@ -694,7 +694,7 @@ $zindex-tooltip: 1070 !default;
// Navs
$nav-link-padding-y: .5rem !default;
$nav-link-padding-x: 1rem !default;
$nav-link-padding-x: 1.25rem !default;
$nav-link-disabled-color: $gray-600 !default;
$nav-tabs-border-color: $gray-300 !default;
@ -731,6 +731,8 @@ $navbar-toggler-padding-x: .75rem !default;
$navbar-toggler-font-size: $font-size-lg !default;
$navbar-toggler-border-radius: $btn-border-radius !default;
$navbar-nav-scroll-max-height: 75vh !default;
$navbar-dark-color: rgba($white, .5) !default;
$navbar-dark-hover-color: rgba($white, .75) !default;
$navbar-dark-active-color: $white !default;
@ -772,12 +774,12 @@ $dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175) !default;
$dropdown-link-color: $gray-900 !default;
$dropdown-link-hover-color: darken($gray-900, 5%) !default;
$dropdown-link-hover-bg: $gray-100 !default;
$dropdown-link-hover-bg: $gray-200 !default;
$dropdown-link-active-color: $component-active-color !default;
$dropdown-link-active-bg: $component-active-bg !default;
$dropdown-link-disabled-color: $gray-600 !default;
$dropdown-link-disabled-color: $gray-500 !default;
$dropdown-item-padding-y: .25rem !default;
$dropdown-item-padding-x: 1.5rem !default;
@ -816,6 +818,8 @@ $pagination-disabled-color: $gray-600 !default;
$pagination-disabled-bg: $white !default;
$pagination-disabled-border-color: $gray-300 !default;
$pagination-border-radius-sm: $border-radius-sm !default;
$pagination-border-radius-lg: $border-radius-lg !default;
// Jumbotron
@ -1054,7 +1058,7 @@ $figure-caption-color: $gray-600 !default;
$breadcrumb-font-size: null !default;
$breadcrumb-padding-y: .75rem !default;
$breadcrumb-padding-x: 1rem !default;
$breadcrumb-padding-x: .5rem !default;
$breadcrumb-item-padding: .5rem !default;
$breadcrumb-margin-bottom: 1rem !default;

View file

@ -1,7 +1,7 @@
/*!
* Bootstrap Grid v4.5.3 (https://getbootstrap.com/)
* Copyright 2011-2020 The Bootstrap Authors
* Copyright 2011-2020 Twitter, Inc.
* Bootstrap Grid v4.6.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
@ -19,6 +19,7 @@ html {
@import "functions";
@import "variables";
@import "mixins/deprecate";
@import "mixins/breakpoints";
@import "mixins/grid-framework";
@import "mixins/grid";

View file

@ -1,7 +1,7 @@
/*!
* Bootstrap Reboot v4.5.3 (https://getbootstrap.com/)
* Copyright 2011-2020 The Bootstrap Authors
* Copyright 2011-2020 Twitter, Inc.
* Bootstrap Reboot v4.6.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/

View file

@ -1,7 +1,7 @@
/*!
* Bootstrap v4.5.3 (https://getbootstrap.com/)
* Copyright 2011-2020 The Bootstrap Authors
* Copyright 2011-2020 Twitter, Inc.
* Bootstrap v4.6.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/

View file

@ -64,6 +64,13 @@
color: color-yiq($color);
background-color: rgba($color, $form-feedback-tooltip-opacity);
@include border-radius($form-feedback-tooltip-border-radius);
// See https://github.com/twbs/bootstrap/pull/31557
// Align tooltip to form elements
.form-row > .col > &,
.form-row > [class*="col-"] > & {
left: $form-grid-gutter-width / 2;
}
}
@include form-validation-state-selector($state) {
@ -108,7 +115,7 @@
@if $enable-validation-icons {
padding-right: $custom-select-feedback-icon-padding-right;
background: $custom-select-background, escape-svg($icon) $custom-select-bg no-repeat $custom-select-feedback-icon-position / $custom-select-feedback-icon-size;
background: $custom-select-background, $custom-select-bg escape-svg($icon) $custom-select-feedback-icon-position / $custom-select-feedback-icon-size no-repeat;
}
&:focus {

View file

@ -26,7 +26,7 @@
// Autoprefixer takes care of adding -webkit-min-device-pixel-ratio and -o-min-device-pixel-ratio,
// but doesn't convert dppx=>dpi.
// There's no such thing as unprefixed min-device-pixel-ratio since it's nonstandard.
// Compatibility info: https://caniuse.com/#feat=css-media-resolution
// Compatibility info: https://caniuse.com/css-media-resolution
@media only screen and (min-resolution: 192dpi), // IE9-11 don't support dppx
only screen and (min-resolution: 2dppx) { // Standardized
background-image: url($file-2x);

View file

@ -1,3 +1,3 @@
@import 'dev/scss/wvc-theme/flatly/variables';
@import 'dev/scss/bootstrap-overrides.scss';
@import 'dev/scss/wvc-theme/flatly/bootswatch';
@import 'dev/scss//wvc-theme/flatly/variables';
@import 'dev/scss//bootstrap-overrides.scss';
@import 'dev/scss//wvc-theme/flatly/bootswatch';

View file

@ -1,4 +1,4 @@
// Cerulean 4.5.3
// Cerulean 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Cerulean 4.5.3
// Cerulean 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// Cosmo 4.5.3
// Cosmo 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Cosmo 4.5.3
// Cosmo 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// Cyborg 4.5.3
// Cyborg 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Cyborg 4.5.3
// Cyborg 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// Darkly 4.5.3
// Darkly 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Darkly 4.5.3
// Darkly 4.6.0
// Bootswatch
//
@ -83,7 +83,7 @@ $dropdown-link-hover-bg: $primary !default;
// Navs
$nav-link-padding-x: 1.5rem !default;
$nav-link-padding-x: 1.25rem !default;
$nav-link-disabled-color: $gray-500 !default;
$nav-tabs-border-color: $gray-700 !default;
$nav-tabs-link-hover-border-color: $nav-tabs-border-color $nav-tabs-border-color transparent !default;

View file

@ -1,4 +1,4 @@
// Flatly 4.5.3
// Flatly 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Flatly 4.5.3
// Flatly 4.6.0
// Bootswatch
//
@ -66,7 +66,7 @@ $dropdown-link-hover-bg: $primary !default;
// Navs
$nav-link-padding-y: .5rem !default !default;
$nav-link-padding-x: 1.5rem !default;
$nav-link-padding-x: 1.25rem !default;
$nav-link-disabled-color: $gray-600 !default !default;
$nav-tabs-border-color: $gray-200 !default;

View file

@ -1,4 +1,4 @@
// Journal 4.5.3
// Journal 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Journal 4.5.3
// Journal 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// Litera 4.5.3
// Litera 4.6.0
// Bootswatch
// Navbar ======================================================================
@ -24,20 +24,6 @@
}
}
// Buttons =====================================================================
.btn {
border-radius: 1.078em;
&-lg {
border-radius: 2.688em;
}
&-sm {
border-radius: .844em;
}
}
// Typography ==================================================================
p {

View file

@ -1,4 +1,4 @@
// Litera 4.5.3
// Litera 4.6.0
// Bootswatch
//
@ -65,6 +65,10 @@ $btn-font-family: $font-family-sans-serif !default;
$btn-font-size: .875rem !default;
$btn-font-size-sm: .688rem !default;
$btn-border-radius: 1.078em !default;
$btn-border-radius-lg: 2.688em !default;
$btn-border-radius-sm: .844em !default;
// Forms
$input-border-color: rgba(0, 0, 0, .1) !default;
@ -72,8 +76,6 @@ $input-group-addon-bg: $gray-200 !default !default;
// Navbar
$navbar-padding-y: .7rem !default;
$navbar-dark-color: rgba($white, .6) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-hover-color: $body-color !default;
@ -86,8 +88,8 @@ $tooltip-font-size: 11px !default;
// Badges
$badge-font-weight: 400 !default;
$badge-padding-y: .3em !default;
$badge-padding-x: .6em !default;
$badge-padding-y: .6em !default;
$badge-padding-x: 1.2em !default;
// Alerts

View file

@ -1,4 +1,4 @@
// Lumen 4.5.3
// Lumen 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Lumen 4.5.3
// Lumen 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// Lux 4.5.3
// Lux 4.6.0
// Bootswatch
@ -22,7 +22,7 @@ $web-font-path: "https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;6
}
&-brand {
margin-right: 1rem;
margin-right: 2rem;
}
}
@ -43,7 +43,7 @@ $web-font-path: "https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;6
}
.nav-item {
margin-right: 1rem;
margin-right: .5rem;
}
// Buttons =====================================================================

View file

@ -1,4 +1,4 @@
// Lux 4.5.3
// Lux 4.6.0
// Bootswatch
//
@ -72,12 +72,12 @@ $input-btn-border-width: 0 !default;
// Buttons
$btn-line-height: 1.5rem !default;
$input-btn-padding-y: .6rem !default;
$input-btn-padding-x: 1.2rem !default;
$input-btn-padding-y-sm: .4rem !default;
$input-btn-padding-x-sm: .8rem !default;
$input-btn-padding-y-lg: 2rem !default;
$input-btn-padding-x-lg: 2rem !default;
$input-btn-padding-y: .5rem !default;
$input-btn-padding-x: 1rem !default;
$input-btn-padding-y-sm: .25rem !default;
$input-btn-padding-x-sm: .75rem !default;
$input-btn-padding-y-lg: 1rem !default;
$input-btn-padding-x-lg: 1rem !default;
$btn-font-weight: 600 !default;
// Forms
@ -95,6 +95,7 @@ $navbar-light-color: rgba($black, .3) !default;
$navbar-light-hover-color: $gray-900 !default;
$navbar-light-active-color: $gray-900 !default;
// Pagination
$pagination-border-color: transparent !default;

View file

@ -1,4 +1,4 @@
// Materia 4.5.3
// Materia 4.6.0
// Bootswatch
@ -287,7 +287,7 @@ select,
select.form-control {
appearance: none;
padding: .5rem 0;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='4' viewBox='0 0 8 4'%3E%3Cpolygon fill='%23666' points='8 0 4 4 0 0'/%3E%3C/svg%3E%0A");
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='4' viewBox='0 0 8 4'%3e%3cpolygon fill='%23666' points='8 0 4 4 0 0'/%3e%3c/svg%3e%0a");
background-size: 8px 4px;
background-repeat: no-repeat;
background-position: right center;
@ -309,7 +309,7 @@ select.form-control {
&:focus {
box-shadow: inset 0 -2px 0 $primary;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='4' viewBox='0 0 8 4'%3E%3Cpolygon fill='%23212121' points='8 0 4 4 0 0'/%3E%3C/svg%3E%0A");
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='4' viewBox='0 0 8 4'%3e%3cpolygon fill='%23212121' points='8 0 4 4 0 0'/%3e%3c/svg%3e%0a");
}
&[multiple] {

View file

@ -1,4 +1,4 @@
// Materia 4.5.3
// Materia 4.6.0
// Bootswatch
//
@ -54,12 +54,12 @@ $font-weight-base: 400 !default;
// Buttons
$input-btn-padding-y: .8rem !default;
$input-btn-padding-y: .5rem !default;
$input-btn-padding-x: 1rem !default;
// Forms
$input-padding-y: 1rem !default;
$input-padding-y: .5rem !default;
$input-padding-x: 0 !default;
$input-padding-y-sm: 0 !default;
$input-padding-x-sm: 0 !default;

View file

@ -1,4 +1,4 @@
// Minty 4.5.3
// Minty 4.6.0
// Bootswatch
@ -33,7 +33,7 @@ $web-font-path: "https://fonts.googleapis.com/css2?family=Montserrat:wght@400;50
&-light,
&-light:hover {
color: $gray-700;
color: $gray-900;
}
&-link,

View file

@ -1,4 +1,4 @@
// Minty 4.5.3
// Minty 4.6.0
// Bootswatch
//
@ -34,7 +34,7 @@ $success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$light: $primary !default;
$dark: $gray-800 !default;
$yiq-contrasted-threshold: 250 !default;
@ -54,7 +54,6 @@ $border-radius-sm: .3rem !default;
// stylelint-disable-next-line value-keyword-case
$headings-font-family: Montserrat, -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default;
$headings-color: $gray-700 !default;
$font-size-base: .875rem !default;
// Tables
@ -67,8 +66,6 @@ $dropdown-link-hover-bg: $secondary !default;
// Navbar
$navbar-padding-y: .7rem !default;
$navbar-dark-color: rgba($white, .6) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-color: rgba($black, .3) !default;

View file

@ -1,4 +1,4 @@
// Pulse 4.5.3
// Pulse 4.6.0
// Bootswatch
// Buttons =====================================================================

View file

@ -1,4 +1,4 @@
// Pulse 4.5.3
// Pulse 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// Sandstone 4.5.3
// Sandstone 4.6.0
// Bootswatch
@ -22,7 +22,7 @@ $web-font-path: "https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;70
}
.sandstone {
font-size: 11px;
font-size: 12px;
line-height: 22px;
font-weight: 500;
text-transform: uppercase;

View file

@ -1,4 +1,4 @@
// Sandstone 4.5.3
// Sandstone 4.6.0
// Bootswatch
//
@ -51,7 +51,7 @@ $link-color: $success !default;
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$font-size-base: .875rem !default;
$font-size-base: .975rem !default;
$headings-font-weight: 400 !default;
// Dropdowns
@ -64,7 +64,7 @@ $dropdown-link-active-bg: $dropdown-link-hover-bg !default;
// Navs
$nav-link-padding-x: .9rem !default;
$nav-link-padding-x: 1.25rem !default;
$nav-link-disabled-color: $gray-300 !default;
$nav-tabs-border-color: $gray-300 !default;
$nav-tabs-link-hover-border-color: $gray-300 !default;

View file

@ -1,4 +1,4 @@
// Simplex 4.5.3
// Simplex 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Simplex 4.5.3
// Simplex 4.6.0
// Bootswatch
//
@ -54,7 +54,7 @@ $dropdown-link-hover-bg: $primary !default;
// Navs
$nav-link-padding-y: .7rem !default;
$nav-link-padding-y: .9rem !default;
$nav-link-disabled-color: $gray-400 !default;
$nav-tabs-border-color: darken(#fff, 6.5%) !default;

View file

@ -1,4 +1,4 @@
// Sketchy 4.5.3
// Sketchy 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Sketchy 4.5.3
// Sketchy 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// Slate 4.5.3
// Slate 4.6.0
// Bootswatch
@ -525,7 +525,7 @@ legend {
}
.list-group {
&-item:hover {
&-item-action:hover {
background-color: darken($gray-900, 5%);
}
}

View file

@ -1,4 +1,4 @@
// Slate 4.5.3
// Slate 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// Solar 4.5.3
// Solar 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Solar 4.5.3
// Solar 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// Spacelab 4.5.3
// Spacelab 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Spacelab 4.5.3
// Spacelab 4.6.0
// Bootswatch
//
@ -51,14 +51,16 @@ $link-color: $info !default;
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$font-size-base: .9375rem !default;
$font-size-sm: $font-size-base * .88 !default;
$headings-font-weight: 300 !default;
$headings-color: $gray-900 !default;
// Navbar
$navbar-padding-y: .7rem !default;
$navbar-dark-color: rgba($white, .75) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-color: rgba($black, .4) !default;
$navbar-light-hover-color: $info !default;
$navbar-light-active-color: $info !default;
$navbar-padding-y: .7rem !default;

View file

@ -1,4 +1,4 @@
// Superhero 4.5.3
// Superhero 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Superhero 4.5.3
// Superhero 4.6.0
// Bootswatch
//

View file

@ -1,4 +1,4 @@
// United 4.5.3
// United 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// United 4.5.3
// United 4.6.0
// Bootswatch
//
@ -34,7 +34,7 @@ $success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-200 !default;
$light: $gray-100 !default;
$dark: $purple !default;
$yiq-contrasted-threshold: 200 !default;
@ -53,6 +53,13 @@ $font-family-sans-serif: Ubuntu, -apple-system, BlinkMacSystemFont, "Segoe
$table-dark-bg: $dark !default;
$table-dark-border-color: darken($dark, 5%) !default;
// Navbar
$navbar-padding-y: .7rem !default;
// Breadcrumb
$breadcrumb-padding-y: .75rem !default;
$breadcrumb-padding-x: .25rem !default;
$breadcrumb-item-padding: .25rem !default;

View file

@ -1,4 +1,4 @@
// Yeti 4.5.3
// Yeti 4.6.0
// Bootswatch

View file

@ -1,4 +1,4 @@
// Yeti 4.5.3
// Yeti 4.6.0
// Bootswatch
//

View file

@ -204,10 +204,6 @@ class Instance(models.Model):
def formats(self):
return self.proxy.get_image_formats()
@cached_property
def interfaces(self):
return self.proxy.get_ifaces()
class PermissionSet(models.Model):
"""

View file

@ -27,7 +27,7 @@
{% for c_net in networks_host %}
<option value="net:{{ c_net }}">Network {{ c_net }}</option>
{% endfor %}
{% for c_iface in instance.interfaces %}
{% for c_iface in interfaces_host %}
<option value="iface:{{ c_iface }}">Interface {{ c_iface }}</option>
{% endfor %}
</select>

View file

@ -54,7 +54,14 @@
{{ ipv4 }} |
{% endfor %}
{% endfor %}
<a class="text-secondary" href="{% url 'instances:instance' instance.id %}" title="{% trans 'Refresh instance info' %}"><span class="fa fa-refresh"></span></a>
{% if instance.guest_agent_ready %}
<a class="text-secondary" title="{% trans 'Show Instance OS details' %}" onclick="get_osinfo()">
<span class="fa fa-info-circle"></span>
</a>
{% endif %}
<a class="text-secondary" href="{% url 'instances:instance' instance.id %}" title="{% trans 'Refresh instance info' %}">
<span class="fa fa-refresh"></span>
</a>
</div>
{% if user_quota_msg %}
<div class="alert alert-warning fade show">
@ -71,13 +78,13 @@
<ul class="nav nav-pills" id="navbtn" aria-label="Instance actions">
<li class="nav-item">
<a href="#power" class="nav-link action-button active" aria-controls="power" role="tab" data-toggle="tab">
<i id="action-block" class="fa fa-power-off fa-2x" aria-hidden="true"></i>
<span id="action-block" class="fa fa-power-off fa-2x" aria-hidden="true"></span>
{% trans "Power" %}
</a>
</li>
<li class="nav-item">
<a href="#access" class="nav-link action-button" aria-controls="access" role="tab" data-toggle="tab">
<i id="action-block" class="fa fa-lock" aria-hidden="true"></i>
<span id="action-block" class="fa fa-lock" aria-hidden="true"></span>
{% trans "Access" %}
</a>
</li>
@ -684,7 +691,7 @@
}
});
}
if (~$.inArray(hash, ['#boot_opt', "#disks", '#network', '#clone', '#xmledit', '#vncsettings', '#migrate', '#options', '#users'])) {
if (~$.inArray(hash, ['#osinfo', '#boot_opt', "#disks", '#network', '#clone', '#xmledit', '#vncsettings', '#migrate', '#options', '#users'])) {
var btnsect = $('#navbtn>li>a');
$(btnsect).each(function () {
if ($(this).attr('href') === '#settings') {
@ -715,4 +722,22 @@
});
}
</script>
<script>
function get_osinfo() {
$('#navbtn a[href="#settings"]').tab('show');
$('#settings a[href="#osinfo"]').tab('show');
$.getJSON('{% url 'instances:osinfo' instance.id %}', function (data) {
$.each(data, function() {
$('#oshostname').text(data['host-name']);
$('#osname').text(data.id);
$('#osprettyname').text(data['pretty-name']);
$('#oskernelrelease').text(data['kernel-release']);
$('#oskernelversion').text(data['kernel-version']);
$('#osversion').text(data.version);
$('#ostimezone').text(data.zone + " / " + data.offset);
})
});
}
</script>
{% endblock %}

View file

@ -1,6 +1,5 @@
{% load i18n %}
<div role="tabpanel" class="tab-pane" id="access" aria-label="Instance access options">
<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
@ -163,7 +162,6 @@
</div>
{% endif %}
</div>
</div>
</div>
{% block script %}
<script>

View file

@ -1,6 +1,5 @@
{% load i18n %}
<div role="tabpanel" class="tab-pane" id="undefine">
<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist" aria-label="Instance destroy menu">
<li class="nav-item">
@ -25,5 +24,4 @@
<div class="clearfix"></div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,20 @@
{% load i18n %}
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="osinfo">
<h3 class="page-header">{% trans "Guest Info" %}</h3>
<dl class="mx-3 row">
<dt class="col-3">{% trans "Hostname" %}</dt>
<dd class="col-9" id="oshostname"></dd>
<dt class="col-3">{% trans "OS Name" %}</dt>
<dd class="col-9" id="osname"></dd>
<dt class="col-3">{% trans "OS Pretty-Name" %}</dt>
<dd class="col-9" id="osprettyname"></dd>
<dt class="col-3">{% trans "Version" %}</dt>
<dd class="col-9" id="osversion"></dd>
<dt class="col-3">{% trans "Kernel Release" %}</dt>
<dd class="col-9" id="oskernelrelease"></dd>
<dt class="col-3">{% trans "Kernel Version" %}</dt>
<dd class="col-9" id="oskernelversion"></dd>
<dt class="col-3">{% trans "Timezone / Offset" %}</dt>
<dd class="col-9" id="ostimezone"></dd>
</dl>
</div>

View file

@ -1,6 +1,5 @@
{% load i18n %}
<div role="tabpanel" class="tab-pane active" id="power">
<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist" aria-label="Instance power actions">
{% if instance.status == 1 %}
@ -127,5 +126,4 @@
</div>
{% endif %}
</div>
</div>
</div>

View file

@ -1,6 +1,5 @@
{% load i18n %}
<div role="tabpanel" class="tab-pane" id="resize">
<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist" aria-label="Instance resize options">
<li class="nav-item">
@ -160,5 +159,4 @@
<div class="clearfix"></div>
</div>
</div>
</div>
</div>

View file

@ -2,11 +2,18 @@
{% load bootstrap4 %}
{% load icons %}
<div role="tabpanel" class="tab-pane" id="settings">
<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist" aria-label="Instance settings">
{% if request.user.is_superuser %}
<li class="nav-item ">
{% if instance.guest_agent_ready %}
<li class="nav-item">
<a class="px-1 nav-link text-secondary" href="#osinfo" aria-controls="os-info" role="tab" data-toggle="tab" onclick="get_osinfo()">
<span class="fa fa-info-circle"></span>
</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link text-secondary active" href="#boot_opt" aria-controls="boot" role="tab" data-toggle="tab">
{% trans "Boot" %}
</a>
@ -59,7 +66,7 @@
{% endif %}
{% if request.user.is_superuser %}
<li class="nav-item">
<a class="nav-link text-secondary" href="#users" aria-controls="users" role="tab" data-toggle="tab">
<a class="px-1 nav-link text-secondary" href="#users" aria-controls="users" role="tab" data-toggle="tab">
{% trans "Users" %}
</a>
</li>
@ -68,6 +75,7 @@
<!-- Tab panes -->
<div class="tab-content">
{% if request.user.is_superuser %}
{% include 'instances/info_tab.html' %}
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="boot_opt">
<p class="font-weight-bold">{% trans 'Autostart' %}</p>
<div class="form-group row">
@ -259,7 +267,7 @@
<strong>IO Mode:</strong> {{ disk.io }} <br/>
<strong>Discard:</strong> {{ disk.discard }} <br/>
<strong>Detect Zeroes:</strong> {{ disk.detect_zeroes }}">
<i class="fa fa-info"></i>
<span class="fa fa-info"></span>
</button>
{{ disk.dev }}
</td>
@ -393,7 +401,7 @@
{% for c_net in networks_host %}
<option value="net:{{ c_net }}" {% if c_net == network.nic %} selected {% endif %}>{% trans 'Network' %} {{ c_net }}</option>
{% endfor %}
{% for c_iface in instance.interfaces %}
{% for c_iface in interfaces_host %}
<option value="iface:{{ c_iface }}" {% if c_iface == network.nic %} selected {% endif %}>{% trans 'Interface' %} {{ c_iface }}</option>
{% endfor %}
</select>
@ -513,7 +521,7 @@
<button type="submit" class="btn btn-sm btn-primary"
name="set_qos" data-toggle="modal"
title="{% trans "Edit QoS" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
<i class="fa fa-save"></i>
<span class="fa fa-save"></span>
</button>
</form>
<form action="{% url 'instances:unset_qos' instance.id %}" method="post" role="form" aria-label="Instance QoS configuration form">
@ -670,8 +678,8 @@
</div>
<div class="clearfix"></div>
</div>
{% endif %}
{% if request.user.is_superuser or request.user.is_staff or userinstance.is_vnc %}
{% endif %}
{% if request.user.is_superuser or request.user.is_staff or userinstance.is_vnc %}
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="vncsettings">
<form method="post" action="{% url 'instances:update_console' instance.id %}">
{% csrf_token %}
@ -691,7 +699,7 @@
</form>
<div class="clearfix"></div>
</div>
{% endif %}
{% endif %}
{% if perms.instances.clone_instances %}
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="clone">
<p class="font-weight-bold">{% trans "Create a clone" %}</p>
@ -905,5 +913,4 @@
</div>
{% endif %}
</div>
</div>
</div>

View file

@ -1,7 +1,6 @@
{% load i18n %}
{% load icons %}
<div role="tabpanel" class="tab-pane" id="snapshots">
<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist" aria-label="Instance snapshot menu">
<li class="nav-item">
@ -79,5 +78,4 @@
{% endif %}
</div>
</div>
</div>
</div>

View file

@ -1,6 +1,5 @@
{% load i18n %}
<div role="tabpanel" class="tab-pane" id="graphics">
<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist" aria-label="Instance graphs and logs menu">
<li class="nav-item">
@ -95,7 +94,6 @@
<div class="clearfix"></div>
</div>
</div>
</div>
</div>
<script>
function update_logs_table(vname) {

View file

@ -20,6 +20,7 @@ urlpatterns = [
path('<int:pk>/migrate/', views.migrate, name='migrate'),
path('<int:pk>/status/', views.status, name='status'),
path('<int:pk>/stats/', views.stats, name='stats'),
path('<int:pk>/osinfo/', views.osinfo, name='osinfo'),
path('<int:pk>/rootpasswd/', views.set_root_pass, name='rootpasswd'),
path('<int:pk>/add_public_key/', views.add_public_key, name='add_public_key'),
path('<int:pk>/resizevm_cpu/', views.resizevm_cpu, name='resizevm_cpu'),

View file

@ -169,17 +169,15 @@ def refr(compute):
if compute.status is True:
domains = compute.proxy.wvm.listAllDomains()
domain_names = [d.name() for d in domains]
domain_uuids = [d.UUIDString() for d in domains]
# Delete instances that're not on host
Instance.objects.filter(compute=compute).exclude(name__in=domain_names).delete()
Instance.objects.filter(compute=compute).exclude(uuid__in=domain_uuids).delete()
# Create instances that're not in DB
names = Instance.objects.filter(compute=compute).values_list('name', flat=True)
uuids = Instance.objects.filter(compute=compute).values_list('uuid', flat=True)
for domain in domains:
if domain.name() not in names:
Instance(compute=compute, name=domain.name(), uuid=domain.UUIDString()).save()
continue
if domain.UUIDString() not in uuids:
Instance(compute=compute, name=domain.name(), uuid=domain.UUIDString()).save()
def get_dhcp_mac_address(vname):

View file

@ -25,6 +25,7 @@ from logs.views import addlogmsg
from vrtManager import util
from vrtManager.create import wvmCreate
from vrtManager.instance import wvmInstances
from vrtManager.interface import wvmInterface
from vrtManager.storage import wvmStorage
from vrtManager.util import randomPasswd
@ -121,6 +122,7 @@ def instance(request, pk):
memory_host = instance.proxy.get_max_memory()
bus_host = instance.proxy.get_disk_bus_types(instance.arch, instance.machine)
networks_host = sorted(instance.proxy.get_networks())
interfaces_host = sorted(instance.proxy.get_ifaces())
nwfilters_host = instance.proxy.get_nwfilters()
storages_host = sorted(instance.proxy.get_storages(True))
net_models_host = instance.proxy.get_network_models()
@ -161,6 +163,11 @@ def stats(request, pk):
}
)
def osinfo(request, pk):
instance = get_instance(request.user, pk)
results = instance.proxy.osinfo()
return JsonResponse(results)
def guess_mac_address(request, vname):
data = {"vname": vname}
@ -764,7 +771,7 @@ def revert_snapshot(request, pk):
msg = _("Successful revert snapshot: ")
msg += snap_name
messages.success(request, msg)
msg = _("Revert snapshot: %(snap)") % {"snap": snap_name}
msg = _("Revert snapshot: %(snap)s") % {"snap": snap_name}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot")
@ -882,7 +889,7 @@ def set_video_model(request, pk):
instance = get_instance(request.user, pk)
video_model = request.POST.get("video_model", "vga")
instance.proxy.set_video_model(video_model)
msg = _("Set Video Model: %(model)") % {"model": video_model}
msg = _("Set Video Model: %(model)s") % {"model": video_model}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get("HTTP_REFERER") + "#options")
@ -899,6 +906,16 @@ def change_network(request, pk):
(source, source_type) = utils.get_network_tuple(request.POST.get(post))
network_data[post] = source
network_data[post + "-type"] = source_type
if source_type == 'iface':
iface = wvmInterface(
instance.compute.hostname,
instance.compute.login,
instance.compute.password,
instance.compute.type,
source,
)
network_data[post + "-type"] = iface.get_type()
elif post.startswith("net-"):
network_data[post] = request.POST.get(post, "")
@ -918,6 +935,16 @@ def add_network(request, pk):
nwfilter = request.POST.get("add-net-nwfilter")
(source, source_type) = utils.get_network_tuple(request.POST.get("add-net-network"))
if source_type == 'iface':
iface = wvmInterface(
instance.compute.hostname,
instance.compute.login,
instance.compute.password,
instance.compute.type,
source,
)
source_type = iface.get_type()
instance.proxy.add_network(mac, source, source_type, nwfilter=nwfilter)
msg = _("Add network: %(mac)s") % {"mac": mac}
addlogmsg(request.user.username, instance.name, msg)

View file

@ -29,7 +29,8 @@ def interfaces(request, compute_id):
netdevs = ["eth0", "eth1"]
for iface in ifaces:
ifaces_all.append(conn.get_iface_info(iface))
interf = wvmInterface(compute.hostname, compute.login, compute.password, compute.type, iface)
ifaces_all.append(interf.get_details())
if request.method == "POST":
if "create" in request.POST:

View file

@ -296,12 +296,12 @@
<button type="submit" class="btn btn-sm btn-primary"
name="modify_fixed_address"
title="{% trans "Edit entry" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
<i class="fa fa-save"></i>
<span class="fa fa-save"></span>
</button>
<button type="submit" class="btn btn-sm btn-danger"
name="delete_fixed_address"
title="{% trans "Delete entry" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
<i class="fa fa-trash"></i>
<span class="fa fa-trash"></span>
</button>
</td>
</form>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
static/js/jquery.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,3 @@
/*! js-cookie v2.2.0 | MIT */
/*! js-cookie v2.2.1 | MIT */
!function(e){var n=!1;if("function"==typeof define&&define.amd&&(define(e),n=!0),"object"==typeof exports&&(module.exports=e(),n=!0),!n){var o=window.Cookies,t=window.Cookies=e();t.noConflict=function(){return window.Cookies=o,t}}}(function(){function e(){for(var e=0,n={};e<arguments.length;e++){var o=arguments[e];for(var t in o)n[t]=o[t]}return n}function n(o){function t(n,r,i){var c;if("undefined"!=typeof document){if(arguments.length>1){if("number"==typeof(i=e({path:"/"},t.defaults,i)).expires){var a=new Date;a.setMilliseconds(a.getMilliseconds()+864e5*i.expires),i.expires=a}i.expires=i.expires?i.expires.toUTCString():"";try{c=JSON.stringify(r),/^[\{\[]/.test(c)&&(r=c)}catch(e){}r=o.write?o.write(r,n):encodeURIComponent(r+"").replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),n=(n=(n=encodeURIComponent(n+"")).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent)).replace(/[\(\)]/g,escape);var s="";for(var f in i)i[f]&&(s+="; "+f,!0!==i[f]&&(s+="="+i[f]));return document.cookie=n+"="+r+s}n||(c={});for(var p=document.cookie?document.cookie.split("; "):[],d=/(%[0-9A-Z]{2})+/g,u=0;u<p.length;u++){var l=p[u].split("="),C=l.slice(1).join("=");this.json||'"'!==C.charAt(0)||(C=C.slice(1,-1));try{var m=l[0].replace(d,decodeURIComponent);if(C=o.read?o.read(C,m):o(C,m)||C.replace(d,decodeURIComponent),this.json)try{C=JSON.parse(C)}catch(e){}if(n===m){c=C;break}n||(c[m]=C)}catch(e){}}return c}}return t.set=t,t.get=function(e){return t.call(t,e)},t.getJSON=function(){return t.apply({json:!0},[].slice.call(arguments))},t.defaults={},t.remove=function(n,o){t(n,"",e(o,{expires:-1}))},t.withConverter=n,t}return n(function(){})});
!function(a){var b;if("function"==typeof define&&define.amd&&(define(a),b=!0),"object"==typeof exports&&(module.exports=a(),b=!0),!b){var c=window.Cookies,d=window.Cookies=a();d.noConflict=function(){return window.Cookies=c,d}}}(function(){function a(){for(var a=0,b={};a<arguments.length;a++){var c=arguments[a];for(var d in c)b[d]=c[d]}return b}function b(a){return a.replace(/(%[0-9A-Z]{2})+/g,decodeURIComponent)}function c(d){function e(){}function f(b,c,f){if("undefined"!=typeof document){f=a({path:"/"},e.defaults,f),"number"==typeof f.expires&&(f.expires=new Date(1*new Date+864e5*f.expires)),f.expires=f.expires?f.expires.toUTCString():"";try{var g=JSON.stringify(c);/^[\{\[]/.test(g)&&(c=g)}catch(j){}c=d.write?d.write(c,b):encodeURIComponent(c+"").replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),b=encodeURIComponent(b+"").replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent).replace(/[\(\)]/g,escape);var h="";for(var i in f)f[i]&&(h+="; "+i,!0!==f[i]&&(h+="="+f[i].split(";")[0]));return document.cookie=b+"="+c+h}}function g(a,c){if("undefined"!=typeof document){for(var e={},f=document.cookie?document.cookie.split("; "):[],g=0;g<f.length;g++){var h=f[g].split("="),i=h.slice(1).join("=");c||'"'!==i.charAt(0)||(i=i.slice(1,-1));try{var j=b(h[0]);if(i=(d.read||d)(i,j)||b(i),c)try{i=JSON.parse(i)}catch(k){}if(e[j]=i,a===j)break}catch(k){}}return a?e[a]:e}}return e.set=f,e.get=function(a){return g(a,!1)},e.getJSON=function(a){return g(a,!0)},e.remove=function(b,c){f(b,"",a(c,{expires:-1}))},e.defaults={},e.withConverter=c,e}return c(function(){})});

View file

@ -482,7 +482,7 @@ class wvmConnect(object):
def get_networks(self):
"""
:return: list of networks
:return: list of host networks
"""
virtnet = []
for net in self.wvm.listNetworks():
@ -493,7 +493,7 @@ class wvmConnect(object):
def get_ifaces(self):
"""
:return: list of network interfaces
:return: list of host interfaces
"""
interface = []
for inface in self.wvm.listInterfaces():

View file

@ -1,3 +1,4 @@
import json
import os.path
import time
@ -20,6 +21,10 @@ try:
VIR_MIGRATE_POSTCOPY,
)
from libvirt import VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT
from libvirt_qemu import (
qemuAgentCommand,
VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT
)
except:
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE
@ -160,6 +165,35 @@ class wvmInstance(wvmConnect):
self._ip_cache = None
self.instance = self.get_instance(vname)
def osinfo(self):
info_results = qemuAgentCommand(
self.instance,
'{"execute":"guest-get-osinfo"}',
VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT, 0
)
timezone_results = qemuAgentCommand(
self.instance,
'{"execute":"guest-get-timezone"}',
VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT, 0
)
hostname_results = qemuAgentCommand(
self.instance,
'{"execute":"guest-get-host-name"}',
VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT, 0
)
info_results = json.loads(info_results).get('return')
timezone_results = json.loads(timezone_results).get('return')
hostname_results = json.loads(hostname_results).get('return')
info_results.update(timezone_results)
info_results.update(hostname_results)
return info_results
def start(self):
self.instance.create()
@ -1332,19 +1366,15 @@ class wvmInstance(wvmConnect):
return bridge_name
def add_network(self, mac_address, source, source_type="net", model="virtio", nwfilter=None):
forward_mode = ""
if source_type != "iface":
forward_mode = self.get_network_forward(source)
if forward_mode in ["nat", "isolated", "routed"]:
if source_type == "net":
interface_type = "network"
elif forward_mode == "":
interface_type = "direct"
else:
if self.get_bridge_name(source, source_type) is None:
interface_type = "network"
else:
elif source_type == "bridge":
interface_type = "bridge"
else:
interface_type = "direct"
# network modes not handled: default is bridge
xml_iface = f"""
<interface type='{interface_type}'>
@ -1352,13 +1382,11 @@ class wvmInstance(wvmConnect):
if interface_type == "network":
xml_iface += f"""<source network='{source}'/>"""
elif interface_type == "direct":
if source_type == "net":
xml_iface += f"""<source network='{source}' mode='bridge'/>"""
else:
xml_iface += f"""<source dev='{source}' mode='bridge'/>"""
elif interface_type == "bridge":
xml_iface += f"""<source bridge='{source}'/>"""
else:
bridge_name = self.get_bridge_name(source, source_type)
xml_iface += f"""<source bridge='{bridge_name}'/>"""
raise libvirtError(f"'{interface_type}' is an unexpected interface type.")
xml_iface += f"""<model type='{model}'/>"""
if nwfilter:
xml_iface += f"""<filterref filter='{nwfilter}'/>"""
@ -1382,8 +1410,35 @@ class wvmInstance(wvmConnect):
self.instance.detachDeviceFlags(new_xml, VIR_DOMAIN_AFFECT_CONFIG)
if self.get_status() == 5:
self.instance.detachDeviceFlags(new_xml, VIR_DOMAIN_AFFECT_CONFIG)
return new_xml
return None
def change_network(self, network_data):
net_mac = network_data.get("net-mac-0")
net_source = network_data.get("net-source-0")
net_source_type = network_data.get("net-source-0-type")
net_filter = network_data.get("net-nwfilter-0")
net_model = network_data.get("net-model-0")
# Remove interface first, but keep network interface XML definition
# If there is an error happened while adding changed one, then add removed one to back.
status = self.delete_network(net_mac)
try:
self.add_network(net_mac, net_source, net_source_type, net_model, net_filter)
except libvirtError:
if status is not None:
if self.get_status() == 1:
self.instance.attachDeviceFlags(status, VIR_DOMAIN_AFFECT_LIVE)
self.instance.attachDeviceFlags(status, VIR_DOMAIN_AFFECT_CONFIG)
if self.get_status() == 5:
self.instance.attachDeviceFlags(status, VIR_DOMAIN_AFFECT_CONFIG)
def change_network_oldway(self, network_data):
'''
change network firsh version...
will be removed if new one works as expected for all scenarios
'''
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
tree = ElementTree.fromstring(xml)
for num, interface in enumerate(tree.findall("devices/interface")):

View file

@ -6,13 +6,6 @@ from vrtManager.connection import wvmConnect
class wvmInterfaces(wvmConnect):
def get_iface_info(self, name):
iface = self.get_iface(name)
xml = iface.XMLDesc(0)
mac = iface.MACString()
itype = util.get_xml_path(xml, "/interface/@type")
state = iface.isActive()
return {"name": name, "type": itype, "state": state, "mac": mac}
def define_iface(self, xml, flag=0):
self.wvm.interfaceDefineXML(xml, flag)
@ -153,6 +146,12 @@ class wvmInterface(wvmConnect):
else:
return None
def get_details(self):
mac = self.get_mac()
itype = self.get_type()
state = self.is_active()
return {"name": self.iface.name(), "type": itype, "state": state, "mac": mac}
def stop_iface(self):
self.iface.destroy()

View file

@ -146,10 +146,12 @@ configure_nginx () {
cp "$APP_PATH"/conf/nginx/webvirtcloud.conf /etc/nginx/conf.d/
if [ -n "$fqdn" ]; then
sed -i "s|\\(#server_name\\).*|server_name = $fqdn|" "$nginxfile"
fqdn_escape="$(echo -n "$fqdn"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
sed -i "s|\\(#server_name\\).*|server_name $fqdn_escape;|" "$nginxfile"
fi
sed -i "s|\\(server 127.0.0.1:\\).*|\\1$novncd_port;|" "$nginxfile"
novncd_port_escape="$(echo -n "$novncd_port"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
sed -i "s|\\(server 127.0.0.1:\\).*|\\1$novncd_port_escape;|" "$nginxfile"
}
@ -157,7 +159,8 @@ configure_supervisor () {
# Copy template supervisor service for gunicorn and novnc
echo " * Copying supervisor configuration"
cp "$APP_PATH"/conf/supervisor/webvirtcloud.conf "$supervisor_conf_path"/"$supervisor_file_name"
sed -i "s|^\\(user=\\).*|\\1$nginx_group|" "$supervisor_conf_path/$supervisor_file_name"
nginx_group_escape="$(echo -n "$nginx_group"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
sed -i "s|^\\(user=\\).*|\\1$nginx_group_escape|" "$supervisor_conf_path/$supervisor_file_name"
}
create_user () {
@ -206,13 +209,18 @@ install_webvirtcloud () {
secret_key=$(generate_secret_key)
echo "* Secret for Django generated: $secret_key"
tzone_escape="$(echo -n "$tzone"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
secret_key_escape="$(echo -n "$secret_key"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
novncd_port_escape="$(echo -n "$novncd_port"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
novncd_public_port_escape="$(echo -n "$novncd_public_port"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
novncd_host_escape="$(echo -n "$novncd_host"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
#TODO escape SED delimiter in variables
sed -i "s|^\\(TIME_ZONE = \\).*|\\1$tzone|" "$APP_PATH/webvirtcloud/settings.py"
sed -i "s|^\\(SECRET_KEY = \\).*|\\1\'$secret_key\'|" "$APP_PATH/webvirtcloud/settings.py"
sed -i "s|^\\(WS_PORT = \\).*|\\1$novncd_port|" "$APP_PATH/webvirtcloud/settings.py"
sed -i "s|^\\(WS_PUBLIC_PORT = \\).*|\\1$novncd_public_port|" "$APP_PATH/webvirtcloud/settings.py"
sed -i "s|^\\(WS_HOST = \\).*|\\1\'$novncd_host\'|" "$APP_PATH/webvirtcloud/settings.py"
sed -i "s|^\\(TIME_ZONE = \\).*|\\1$tzone_escape|" "$APP_PATH/webvirtcloud/settings.py"
sed -i "s|^\\(SECRET_KEY = \\).*|\\1\'$secret_key_escape\'|" "$APP_PATH/webvirtcloud/settings.py"
sed -i "s|^\\(WS_PORT = \\).*|\\1$novncd_port_escape|" "$APP_PATH/webvirtcloud/settings.py"
sed -i "s|^\\(WS_PUBLIC_PORT = \\).*|\\1$novncd_public_port_escape|" "$APP_PATH/webvirtcloud/settings.py"
sed -i "s|^\\(WS_HOST = \\).*|\\1\'$novncd_host_escape\'|" "$APP_PATH/webvirtcloud/settings.py"
echo "* Activate virtual environment."
activate_python_environment
@ -455,7 +463,7 @@ case $distro in
log "yum -y install wget epel-release"
echo "* Installing OS requirements."
PACKAGES="git python3-virtualenv python3-devel libvirt-devel glibc gcc nginx supervisor python3-lxml python3-libguestfs iproute-tc cyrus-sasl-md5 python3-libguestfs"
PACKAGES="git python3-virtualenv python3-devel libvirt-devel glibc gcc nginx supervisor python3-lxml python3-libguestfs iproute-tc cyrus-sasl-md5"
install_packages
set_hosts