Unverified Commit 5c17b1a7 authored by 老广's avatar 老广 Committed by GitHub

Merge pull request #1240 from jumpserver/dev

首次登陆免验证码,首次登录信息变更
parents e865484a ea2863a5
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
__version__ = "1.2.0"
__version__ = "1.2.1"
......@@ -15,9 +15,9 @@
{% csrf_token %}
<h3>{% trans 'Basic' %}</h3>
{% bootstrap_field form.hostname layout="horizontal" %}
{% bootstrap_field form.platform layout="horizontal" %}
{% bootstrap_field form.ip layout="horizontal" %}
{% bootstrap_field form.port layout="horizontal" %}
{% bootstrap_field form.platform layout="horizontal" %}
{% bootstrap_field form.public_ip layout="horizontal" %}
{% bootstrap_field form.domain layout="horizontal" %}
......@@ -85,6 +85,17 @@ $(document).ready(function () {
allowClear: true,
templateSelection: format
});
$("#id_platform").change(function (){
var platform = $("#id_platform option:selected").text();
var port = 22;
if(platform === 'Windows'){
port = 3389;
}
if(platform === 'Other'){
port = null;
}
$("#id_port").val(port);
});
})
</script>
{% endblock %}
\ No newline at end of file
......@@ -304,7 +304,10 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
if v != '':
asset_dict[k] = v
asset = get_object_or_none(Asset, id=asset_dict.pop('id', 0))
asset = None
asset_id = asset_dict.pop('id', None)
if asset_id:
asset = get_object_or_none(Asset, id=asset_id)
if not asset:
try:
if len(Asset.objects.filter(hostname=asset_dict.get('hostname'))):
......
This diff is collapsed.
......@@ -220,7 +220,6 @@
position: relative;
display: block;
text-align: right;
width: 100%;
}
.wizard.vertical > .actions
......
<div class="footer fixed">
<div class="pull-right">
Version <strong>1.2.0-{% include '_build.html' %}</strong> GPLv2.
Version <strong>1.2.1-{% include '_build.html' %}</strong> GPLv2.
<img style="display: none" src="http://www.jumpserver.org/img/evaluate_avatar1.jpg">
</div>
<div>
<strong>Copyright</strong> 北京堆栈科技有限公司 &copy; 2014-2018
</div>
</div>
\ No newline at end of file
</div>
......@@ -6,9 +6,12 @@
{% blocktrans %}
Your information was incomplete. Please click <a href="{{ first_login_url }}"> this link </a>to complete your information.
{% endblocktrans %}
<button aria-hidden="true" data-dismiss="alert" class="close" type="button" style="outline: none;">×</button>
</div>
{% endif %}
{% endblock %}
{% block update_public_key_message %}
{% if request.user.is_authenticated and not request.user.is_public_key_valid and not request.COOKIE.close_public_key_msg != '1' %}
<div class="alert alert-danger help-message alert-dismissable">
......@@ -25,7 +28,9 @@
{% for message in messages %}
<div class="alert alert-{{ message.tags }} help-message" >
{{ message|safe }}
<button aria-hidden="true" data-dismiss="alert" class="close" type="button" style="outline: none;">×</button>
</div>
{% endfor %}
{% endif %}
......
......@@ -153,7 +153,7 @@ class UserOtpAuthApi(APIView):
return Response({'msg': '请先进行用户名和密码验证'}, status=401)
if not check_otp_code(user.otp_secret_key, otp_code):
return Response({'msg': 'otp认证失败'}, status=401)
return Response({'msg': 'MFA认证失败'}, status=401)
token = generate_token(request, user)
self.write_login_log(request, user)
......@@ -204,7 +204,7 @@ class UserAuthApi(APIView):
return Response(
{
'code': 101,
'msg': '请携带seed值,进行OTP二次认证',
'msg': '请携带seed值,进行MFA二次认证',
'otp_url': reverse('api-users:user-otp-auth'),
'seed': seed,
'user': self.serializer_class(user).data
......
......@@ -15,6 +15,14 @@ class UserLoginForm(AuthenticationForm):
label=_('Password'), widget=forms.PasswordInput,
max_length=128, strip=False
)
class UserLoginCaptchaForm(AuthenticationForm):
username = forms.CharField(label=_('Username'), max_length=100)
password = forms.CharField(
label=_('Password'), widget=forms.PasswordInput,
max_length=128, strip=False
)
captcha = CaptchaField()
......@@ -27,7 +35,7 @@ class UserCheckPasswordForm(forms.Form):
class UserCheckOtpCodeForm(forms.Form):
otp_code = forms.CharField(label=_('MFA_code'), max_length=6)
otp_code = forms.CharField(label=_('MFA code'), max_length=6)
class UserCreateUpdateForm(forms.ModelForm):
......@@ -36,7 +44,10 @@ class UserCreateUpdateForm(forms.ModelForm):
label=_('Password'), widget=forms.PasswordInput,
max_length=128, strip=False, required=False,
)
role = forms.ChoiceField(choices=role_choices, required=True, initial=User.ROLE_USER, label=_("Role"))
role = forms.ChoiceField(
choices=role_choices, required=True,
initial=User.ROLE_USER, label=_("Role")
)
public_key = forms.CharField(
label=_('ssh public key'), max_length=5000, required=False,
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
......@@ -47,7 +58,7 @@ class UserCreateUpdateForm(forms.ModelForm):
model = User
fields = [
'username', 'name', 'email', 'groups', 'wechat',
'phone', 'role', 'date_expired', 'comment',
'phone', 'role', 'date_expired', 'comment', 'otp_level'
]
help_texts = {
'username': '* required',
......@@ -61,6 +72,7 @@ class UserCreateUpdateForm(forms.ModelForm):
'data-placeholder': _('Join user groups')
}
),
'otp_level': forms.RadioSelect()
}
def clean_public_key(self):
......@@ -77,11 +89,15 @@ class UserCreateUpdateForm(forms.ModelForm):
def save(self, commit=True):
password = self.cleaned_data.get('password')
otp_level = self.cleaned_data.get('otp_level')
public_key = self.cleaned_data.get('public_key')
user = super().save(commit=commit)
if password:
user.set_password(password)
user.save()
if otp_level:
user.otp_level = otp_level
user.save()
if public_key:
user.public_key = public_key
user.save()
......@@ -105,6 +121,39 @@ class UserProfileForm(forms.ModelForm):
UserProfileForm.verbose_name = _("Profile")
class UserMFAForm(forms.ModelForm):
mfa_description = _(
'Tip: when enabled, '
'you will enter the MFA binding process the next time you log in. '
'you can also directly bind in '
'"personal information -> quick modification -> change MFA Settings"!')
class Meta:
model = User
fields = ['otp_level']
widgets = {'otp_level': forms.RadioSelect()}
help_texts = {
'otp_level': _('* Enable MFA authentication '
'to make the account more secure.'),
}
UserMFAForm.verbose_name = _("MFA")
class UserFirstLoginFinishForm(forms.Form):
finish_description = _(
'In order to protect you and your company, '
'please keep your account, '
'password and key sensitive information properly. '
'(for example: setting complex password, enabling MFA authentication)'
)
UserFirstLoginFinishForm.verbose_name = _("Finish")
class UserPasswordForm(forms.Form):
old_password = forms.CharField(
max_length=128, widget=forms.PasswordInput,
......@@ -147,6 +196,7 @@ class UserPasswordForm(forms.Form):
class UserPublicKeyForm(forms.Form):
pubkey_description = _('Automatically configure and download the SSH key')
public_key = forms.CharField(
label=_('ssh public key'), max_length=5000, required=False,
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
......
......@@ -36,23 +36,52 @@ class User(AbstractUser):
(2, _("Force enable")),
)
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
username = models.CharField(max_length=128, unique=True, verbose_name=_('Username'))
username = models.CharField(
max_length=128, unique=True, verbose_name=_('Username')
)
name = models.CharField(max_length=128, verbose_name=_('Name'))
email = models.EmailField(max_length=128, unique=True, verbose_name=_('Email'))
groups = models.ManyToManyField('users.UserGroup', related_name='users', blank=True, verbose_name=_('User group'))
role = models.CharField(choices=ROLE_CHOICES, default='User', max_length=10, blank=True, verbose_name=_('Role'))
avatar = models.ImageField(upload_to="avatar", null=True, verbose_name=_('Avatar'))
wechat = models.CharField(max_length=128, blank=True, verbose_name=_('Wechat'))
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone'))
otp_level = models.SmallIntegerField(default=0, choices=OTP_LEVEL_CHOICES, verbose_name=_('Enable OTP'))
email = models.EmailField(
max_length=128, unique=True, verbose_name=_('Email')
)
groups = models.ManyToManyField(
'users.UserGroup', related_name='users',
blank=True, verbose_name=_('User group')
)
role = models.CharField(
choices=ROLE_CHOICES, default='User', max_length=10,
blank=True, verbose_name=_('Role')
)
avatar = models.ImageField(
upload_to="avatar", null=True, verbose_name=_('Avatar')
)
wechat = models.CharField(
max_length=128, blank=True, verbose_name=_('Wechat')
)
phone = models.CharField(
max_length=20, blank=True, null=True, verbose_name=_('Phone')
)
otp_level = models.SmallIntegerField(
default=0, choices=OTP_LEVEL_CHOICES, verbose_name=_('MFA')
)
_otp_secret_key = models.CharField(max_length=128, blank=True, null=True)
# Todo: Auto generate key, let user download
_private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Private key'))
_public_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Public key'))
comment = models.TextField(max_length=200, blank=True, verbose_name=_('Comment'))
_private_key = models.CharField(
max_length=5000, blank=True, verbose_name=_('Private key')
)
_public_key = models.CharField(
max_length=5000, blank=True, verbose_name=_('Public key')
)
comment = models.TextField(
max_length=200, blank=True, verbose_name=_('Comment')
)
is_first_login = models.BooleanField(default=True)
date_expired = models.DateTimeField(default=date_expired_default, blank=True, null=True, verbose_name=_('Date expired'))
created_by = models.CharField(max_length=30, default='', verbose_name=_('Created by'))
date_expired = models.DateTimeField(
default=date_expired_default, blank=True, null=True,
verbose_name=_('Date expired')
)
created_by = models.CharField(
max_length=30, default='', verbose_name=_('Created by')
)
def __str__(self):
return '{0.name}({0.username})'.format(self)
......@@ -213,7 +242,9 @@ class User(AbstractUser):
return user_default
def generate_reset_token(self):
return signer.sign_t({'reset': str(self.id), 'email': self.email}, expires_in=3600)
return signer.sign_t(
{'reset': str(self.id), 'email': self.email}, expires_in=3600
)
@property
def otp_enabled(self):
......
......@@ -74,13 +74,11 @@
</article>
<footer>
<div class="" style="margin-top: 100px;">
{% include '_copyright.html' %}
</div>
</footer>
<footer>
<div class="" style="margin-top: 100px;">
{% include '_copyright.html' %}
</div>
</footer>
</body>
</html>
......
......@@ -17,7 +17,10 @@
{% bootstrap_field form.groups layout="horizontal" %}
<div class="hr-line-dashed"></div>
{% block password %} {% endblock %}
<h3>{% trans 'Auth' %}</h3>
{% block password %}{% endblock %}
{% bootstrap_field form.otp_level layout="horizontal" %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Security and Role' %}</h3>
......
......@@ -9,6 +9,7 @@
<link href="{% static 'css/plugins/steps/jquery.steps.css' %}" rel="stylesheet">
{% endblock %}
{% block first_login_message %}{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
......@@ -27,58 +28,116 @@
</div>
<div class="ibox-content">
<div class="wizard">
<div class="steps clearfix">
<ul role="tablist">
{% for step in wizard.steps.all %}
<li role="tab" class="{% ifequal step wizard.steps.first %}first{% endifequal %} {% ifequal step wizard.steps.current %}current{% else %}disabled{% endifequal %} {% ifequal step wizard.steps.last %}last{% endifequal %}"
aria-disabled="false" aria-selected="true">
<a href="javascript:void(0)"><span class="number">{% trans 'Step' %} {{ step }}</span></a>
</li>
{% endfor >%}
</ul>
</div>
<div class="content clearfix">
<form action="" method="post" class="form col-lg-8 p-m" id="fl_form">
{% csrf_token %}
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{% bootstrap_form form %}
{% endfor %}
{% else %}
{% bootstrap_form wizard.form %}
{% endif %}
</form>
</div>
<div class="steps clearfix">
<ul role="tablist">
{% for step in wizard.steps.all %}
<li role="tab" class="{% ifequal step wizard.steps.first %}first{% endifequal %} {% ifequal step wizard.steps.current %}current{% else %}disabled{% endifequal %} {% ifequal step wizard.steps.last %}last{% endifequal %}"
aria-disabled="false" aria-selected="true">
<a class="fl_goto" name="wizard_goto_step" data-goto="{{ step }}">
<span class="number">
{% ifequal step '0' %}
1. {% trans "Profile" %}
{% endifequal %}
{% ifequal step '1' %}
2. {% trans "Public key" %}
{% endifequal %}
{% ifequal step '2' %}
3. {% trans "MFA" %}
{% endifequal %}
{% ifequal step '3' %}
4. {% trans "Finish" %}
{% endifequal %}
</span>
</a>
</li>
{% endfor >%}
</ul>
</div>
<div class="content clearfix" style="background-color: #eee; border-radius:5px;">
<div class="row">
<form action="" method="post" class="form col-lg-8 p-m" id="fl_form" style="padding-left: 40px;">
{% csrf_token %}
{{ wizard.management_form }}
{#{% if wizard.form.forms %}#}
{#{{ wizard.form.management_form }}#}
{#{% for form in wizard.form %}#}
{#{% bootstrap_form form %}#}
{#{% endfor %}#}
{#{% else %}#}
{#{% endif %}#}
{% if form.finish_description %}
<b>{{ form.finish_description }}</b>
<br>
<input type="checkbox" id="acceptTerms">
<label for="acceptTerms" style="margin-top:20px">{% trans "I agree with the terms and conditions." %}</label>
{% endif %}
{% bootstrap_form wizard.form %}
{% if form.mfa_description %}
<b>{{ form.mfa_description }}</b>
{% endif %}
{% if form.pubkey_description %}
<span>或者:</span>
<a type="button" id="btn-reset-pubkey">{{ form.pubkey_description }}</a>
{% endif %}
</form>
<div class="col-lg-4">
<div class="text-center">
<div style="margin-top: 20px">
<i class="fa fa-sign-in" style="font-size: 180px;color: #e5e5e5 "></i>
</div>
</div>
</div>
</div>
</div>
<div class="actions clearfix">
<ul>
{% if wizard.steps.prev %}
<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.prev }}">{% trans "Previous" %}</a></li>
{% endif %}
{% if wizard.steps.next %}
<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.next }}">{% trans "Next" %}</a></li>
{% endif %}
<li><a id="fl_submit">{% trans "Submit" %}</a></li>
</ul>
<ul>
{% if wizard.steps.prev %}
<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.prev }}">{% trans "Previous" %}</a></li>
{% endif %}
{#{% if wizard.steps.next %}#}
{#<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.next }}">{% trans "Next" %}</a></li>#}
{#{% endif %}#}
{#<li><a id="fl_submit">{% trans "Submit" %}</a></li>#}
{#将原来的下一页-替换为提交;修复 每页都提交,最后才能成功问题#}
{% if wizard.steps.next %}
<li><a id="fl_submit" >{% trans "Next" %}</a></li>
{% else %}
<li><a id="fl_submit" style="width:66px;text-align: center;">{% trans "Finish" %}</a></li>
{% endif %}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
$(document).on('click', ".fl_goto", function(){
var $form = $('#fl_form');
$('<input />', {'name': 'wizard_goto_step', 'value': $(this).data('goto'), 'type': 'hidden'}).appendTo($form);
$form.submit();
return false;
}).on('click', '#fl_submit', function(){
$('#fl_form').submit();
return false;
$('#id_2-otp_level div').eq(2).css('display', 'none');
$(document).on('click', ".fl_goto", function(){
var $form = $('#fl_form');
$('<input />', {'name': 'wizard_goto_step', 'value': $(this).data('goto'), 'type': 'hidden'}).appendTo($form);
$form.submit();
return false;
}).on('click', '#fl_submit', function(){
$('#fl_form').submit();
return false;
}).on('click', '#btn-reset-pubkey', function () {
var the_url = '{% url "users:user-pubkey-generate" %}';
window.open(the_url, "_blank")
})
</script>
{% endblock %}
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load bootstrap3 %}
{% load bootstrap3 %}
{% block custom_head_css_js %}
......@@ -9,6 +9,7 @@
<link href="{% static 'css/plugins/steps/jquery.steps.css' %}" rel="stylesheet">
{% endblock %}
{% block first_login_message %}{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
......@@ -36,6 +37,8 @@
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
$(document).on('click', ".fl_goto", function(){
......
......@@ -53,7 +53,7 @@
{% endif %}
{% endif %}
<div class="form-group">
<input type="text" class="form-control" name="{{ form.username.html_name }}" placeholder="{% trans 'Username' %}" required="">
<input type="text" class="form-control" name="{{ form.username.html_name }}" placeholder="{% trans 'Username' %}" required="" value="{% if form.username.value %}{{ form.username.value }}{% endif %}">
</div>
<div class="form-group">
<input type="password" class="form-control" name="{{ form.password.html_name }}" placeholder="{% trans 'Password' %}" required="">
......
......@@ -6,11 +6,11 @@
{# {% bootstrap_field form.username layout="horizontal" %}#}
{#{% endblock %}#}
{% block password %}
<h3>{% trans 'Auth' %}</h3>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans 'Password' %}</label>
<div class="col-sm-8 controls" >
<div class="col-sm-8 controls" style="margin-top: 8px;">
{% trans 'Reset link will be generated and sent to the user. ' %}
</div>
</div>
{% endblock %}
\ No newline at end of file
{% endblock %}
......@@ -107,6 +107,9 @@ $(document).ready(function(){
$('.btn_export').click(function () {
var users = [];
var rows = table.rows('.selected').data();
if(rows.length===0){
rows = table.rows().data();
}
$.each(rows, function (index, obj) {
users.push(obj.id)
});
......
......@@ -27,7 +27,6 @@
$(function(){
$('.change-color li').eq(2).remove();
$('.change-color li:eq(1) div').eq(1).html('解绑MFA')
})
......
......@@ -3,7 +3,6 @@
{% load bootstrap3 %}
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
{% block password %}
<h3>{% trans 'Auth' %}</h3>
{% bootstrap_field form.password layout="horizontal" %}
{% bootstrap_field form.public_key layout="horizontal" %}
{% endblock %}
......@@ -2,6 +2,7 @@
from __future__ import unicode_literals
import os
from django.core.cache import cache
from django.shortcuts import render
from django.contrib.auth import login as auth_login, logout as auth_logout
from django.contrib.auth.mixins import LoginRequiredMixin
......@@ -43,7 +44,9 @@ __all__ = [
class UserLoginView(FormView):
template_name = 'users/login.html'
form_class = forms.UserLoginForm
form_class_captcha = forms.UserLoginCaptchaForm
redirect_field_name = 'next'
key_prefix = "_LOGIN_INVALID_{}"
def get(self, request, *args, **kwargs):
if request.user.is_staff:
......@@ -58,6 +61,21 @@ class UserLoginView(FormView):
set_tmp_user_to_cache(self.request, form.get_user())
return redirect(self.get_success_url())
def form_invalid(self, form):
ip = get_login_ip(self.request)
cache.set(self.key_prefix.format(ip), 1, 3600)
old_form = form
form = self.form_class_captcha(data=form.data)
form._errors = old_form.errors
return super().form_invalid(form)
def get_form_class(self):
ip = get_login_ip(self.request)
if cache.get(self.key_prefix.format(ip)):
return self.form_class_captcha
else:
return self.form_class
def get_success_url(self):
user = get_user_or_tmp_user(self.request)
......@@ -166,8 +184,7 @@ class UserForgotPasswordSendmailSuccessView(TemplateView):
'redirect_url': reverse('users:login'),
}
kwargs.update(context)
return super()\
.get_context_data(**kwargs)
return super().get_context_data(**kwargs)
class UserResetPasswordSuccessView(TemplateView):
......@@ -214,7 +231,12 @@ class UserResetPasswordView(TemplateView):
class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
template_name = 'users/first_login.html'
form_list = [forms.UserProfileForm, forms.UserPublicKeyForm]
form_list = [
forms.UserProfileForm,
forms.UserPublicKeyForm,
forms.UserMFAForm,
forms.UserFirstLoginFinishForm
]
file_storage = default_storage
def dispatch(self, request, *args, **kwargs):
......@@ -255,7 +277,6 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
def get_form(self, step=None, data=None, files=None):
form = super().get_form(step, data, files)
form.instance = self.request.user
return form
......@@ -293,7 +314,9 @@ class LoginLogListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
'date_to': self.date_to,
'user': self.user,
'keyword': self.keyword,
'user_list': set(LoginLog.objects.all().values_list('username', flat=True))
'user_list': set(
LoginLog.objects.all().values_list('username', flat=True)
)
}
kwargs.update(context)
return super().get_context_data(**kwargs)
\ No newline at end of file
#!/bin/bash
if [ ! -d "/opt/py3" ]; then
echo -e "\033[31m python3虚拟环境不是默认路径 \033[0m"
ps -ef | grep jumpserver/tmp/beat.pid | grep -v grep
if [ $? -ne 0 ]
then
echo -e "\033[31m jumpserver未运行,请到jumpserver目录使用 ./jms start all -d 启动 \033[0m"
exit 0
else
echo -e "\033[31m 正在计算python3虚拟环境路径 \033[0m"
fi
py3pid=`ps -ef | grep jumpserver/tmp/beat.pid | grep -v grep | awk '{print $2}'`
py3file=`cat /proc/$py3pid/cmdline`
py3even=`echo ${py3file%/bin/python3*}`
echo -e "\033[31m python3虚拟环境路径为$py3even \033[0m"
source $py3even/bin/activate
else
source /opt/py3/bin/activate
fi
cd `dirname $0`/ && cd .. && ./jms stop
jumpserver_backup=/tmp/jumpserver_backup$(date -d "today" +"%Y%m%d_%H%M%S")
mkdir -p $jumpserver_backup
cp -r ./* $jumpserver_backup
echo -e "\033[31m 是否需要备份Jumpserver数据库 \033[0m"
stty erase ^H
read -p "确认备份请按Y,否则按其他键跳过备份 " a
if [ "$a" == y -o "$a" == Y ];then
echo -e "\033[31m 正在备份数据库 \033[0m"
echo -e "\033[31m 请手动输入数据库信息 \033[0m"
read -p '请输入Jumpserver数据库ip:' DB_HOST
read -p '请输入Jumpserver数据库端口:' DB_PORT
read -p '请输入Jumpserver数据库名称:' DB_NAME
read -p '请输入有权限导出数据库的用户:' DB_USER
read -p '请输入该用户的密码:' DB_PASSWORD
mysqldump -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD $DB_NAME > /$jumpserver_backup/$DB_NAME$(date -d "today" +"%Y%m%d_%H%M%S").sql || {
echo -e "\033[31m 备份数据库失败,请检查输入是否有误 \033[0m"
exit 1
}
echo -e "\033[31m 备份数据库完成 \033[0m"
else
echo -e "\033[31m 已取消备份数据库操作 \033[0m"
fi
git pull && pip install -r requirements/requirements.txt && cd utils && sh make_migrations.sh
cd .. && ./jms start all -d
echo -e "\033[31m 请检查jumpserver是否启动成功 \033[0m"
echo -e "\033[31m 备份文件存放于$jumpserver_backup目录 \033[0m"
exit 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment