idea自动构建web项目
系统管理员(sysadmin)每年在重复性任务上浪费数千小时。 幸运的是,使用开源工具构建的Web应用程序可以自动消除很大一部分痛苦。
例如,使用Python和JavaScript构建Web应用程序只需要大约一天的时间。 这是任何Web应用程序必须具有的核心结构:
- 后端来保留数据
- 用于托管和路由流量的Web服务器
- HTML用户界面
- 交互式JavaScript代码,使其更具功能
- CSS布局和样式使其漂亮
场景:简化员工离职
假设您是一家拥有一千名员工的公司的系统管理员。 如果普通员工在三年后离职,则必须每天裁员。 那是一个很大的时间浪费!
员工离职时有很多事情要做:从LDAP中删除其用户帐户,撤消GitHub权限,从薪资中删除他们,更新组织结构图,重定向其电子邮件,撤消其钥匙卡等。
作为系统管理员,您的任务是自动完成工作,因此您已经编写了一些辅助脚本来自动运行IT方面的内容。 但是HR仍然必须打电话给您,并要求您运行每个脚本,这是您不可以做的事情。
您决定花一整天的时间来自动解决此问题,从长远来看可以节省数百小时。 (还有另一个选项,我将在本文结尾处介绍。)
该应用程序将是您可以提供给HR的简单门户。 当HR输入离职用户的电子邮件地址时,该应用程序将在后台运行您的离职脚本。
它的前端是用JavaScript构建的,后端是使用Flask的Python应用程序。 它使用Nginx托管在AWS EC2实例上(或者可以在您的公司网络或私有云中)。 让我们从Python(Flask)应用程序开始依次查看每个元素。
从后端开始
后端允许您向特定的URL发出HTTP POST请求,并传入离职员工的电子邮件地址。 该应用程序为该员工运行脚本,并为每个脚本返回成功或失败。 它使用Flask (Python Web框架),非常适合像这样的轻量级后端。
要安装Flask,请创建一个Python虚拟环境,然后使用pip进行安装:
~ /offboarding$ virtualenv
~ /venv/offboarding
~ /offboarding$ source
~ /venv/offboarding/bin/activate
( offboarding
)
~ /offboarding$ pip3 install flask
Collecting flask
Downloading
...
使用Flask处理请求
通过使用@ app.route(<url>,...) 装饰函数在Flask中创建HTTP端点,并使用request变量访问请求数据。 这是一个Flask端点,可读取员工的电子邮件地址:
#!/usr/bin/env python3
from flask
import Flask
, request
app
= Flask
( __name__
)
@ app.
route
(
'/offboard'
, methods
=
[
'POST'
]
)
def offboard
(
) :
employee_email
= request.
json .
get
(
'employeeEmail'
)
print
(
"Running offboarding for employee {} ..." .
format
( employee_email
)
)
return
'It worked!'
if __name__
==
"__main__" :
app.
run
( threaded
=
True
)
它以状态200和文本“ It work!”响应HTTP请求。 在身体里。 要检查它是否有效,请运行脚本; 这将运行Flask开发服务器,足以进行测试和轻松使用(尽管有警告)。
( offboarding
)
~ /offboarding$ ./offboarding.
py
* Serving Flask app
"offboarding"
( lazy loading
)
* Environment: production
WARNING: This
is a development server.
Do
not use it
in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:
5000 /
( Press CTRL+C to quit
)
这是一个发出请求的curl命令:
~ $ curl -X POST \
-d
'{"employeeEmail": "shaun@anvil.works"}' \
-H
"Content-Type: application/json" \
http://localhost:
5000 /offboard
It worked
!
最后一行是服务器的响应:它正在工作! 这是服务器打印的内容:
Running offboarding
for employee shaun
@ anvil.works ...
127.0.0.1 - -
[ 05
/ Sep
/
2019
13 :
10 :
55
]
"POST /offboard HTTP/1.1"
200 -
它已经启动并运行了! 您有一个可以接收数据的端点。 展开它以使其运行预先存在的辅助脚本。
使用Python运行脚本
为了使事情简单,将脚本放在单个文件夹中并遍历该文件夹,运行您发现的所有内容。 这样,您无需修改代码并重新启动服务器即可将新脚本添加到离职流程中。 您可以将它们复制到文件夹中(或创建符号链接)。
这是修改后的Flask应用程序的外观(代码中的注释指出了一些最佳做法):
#!/usr/bin/env python3
from flask
import Flask
, request
import
subprocess
from pathlib
import Path
import
os
app
= Flask
( __name__
)
# Set the (relative) path to the scripts directory
# so we can easily use a different one.
SCRIPTS_DIR
=
'scripts'
@ app.
route
(
'/offboard'
, methods
=
[
'POST'
]
)
def offboard
(
) :
employee_email
= request.
json .
get
(
'employeeEmail'
)
print
(
"Running offboarding for employee {} ..." .
format
( employee_email
)
)
statuses
=
{
}
for script
in
os .
listdir
( SCRIPTS_DIR
) :
# The pathlib.Path object is a really elegant way to construct paths
# in a way that works cross-platform (IMO!)
path
= Path
( SCRIPTS_DIR
) / script
print
(
' Running {}' .
format
( path
)
)
# This is where we call out to the script and store the exit code.
statuses
[ script
]
=
subprocess .
run
(
[
str
( path
)
, employee_email
]
) .
returncode
return statuses
if __name__
==
"__main__" :
# Running the Flask server in threaded mode allows multiple
# users to connect at once. For a consumer-facing app,
# we would not use the Flask development server, but we expect low traffic!
app.
run
( threaded
=
True
)
将一些可执行文件放在scripts /目录中。 以下是一些执行此操作的shell命令:
mkdir
-p scripts
/
cat
> scripts
/ remove_from_ldap.py
<<EOF
#!/usr/bin/env python3
print('Removing user from LDAP...')
EOF
cat
> scripts
/ revoke_github_permisisons.py
<<EOF
#!/usr/bin/env python3
import sys
sys.exit(1)
EOF
cat
> scripts
/ update_org_chart.sh
<<EOF
#!/bin/sh
echo "Updating org chart for $1..."
EOF
chmod +x scripts
/*
现在,重新启动服务器,然后再次运行curl请求。 响应是一个JSON对象,显示了脚本的退出代码。 看起来revoke_github_permissions.py在此运行中失败:
~ $ curl -X POST \
-d
'{"employeeEmail": "shaun@anvil.works"}' \
-H
"Content-Type: application/json" \
http://localhost:
5000 /offboard
{
"remove_from_ldap.py" :
0
,
"revoke_github_permissions.py" :
1
,
"update_org_chart.sh" :
0
}
这是服务器的输出; 这次它通知我们每个脚本何时开始运行:
Running offboarding
for employee shaun
@ anvil.works ...
Running scripts
/ remove_from_ldap.py
Running scripts
/ revoke_github_permissions.py
Running scripts
/ update_org_chart.sh
127.0.0.1 - -
[ 05
/ Sep
/
2019
13 :
30 :
55
]
"POST /offboard HTTP/1.1"
200 -
现在,您可以通过发出HTTP请求来远程运行脚本。
添加身份验证和访问控制
到目前为止,该应用程序尚未执行任何访问控制,这意味着任何人都可以为任何用户触发非正式使用。 很容易看到如何滥用它,因此您需要添加一些访问控制。
在理想的情况下,您将根据公司标识系统对所有用户进行身份验证。 但是,例如根据Office 365对Flask应用进行身份验证将需要更长的时间 。 因此,请使用“ HTTP Basic”用户名和密码身份验证。
首先,安装Flask-HTTPAuth库:
( offboarding
) ~
/ offboarding$ pip3
install Flask-HTTPAuth
Collecting Flask-HTTPAuth
Downloading …
现在,通过将以下代码添加到offboarding.py的顶部,需要用户名和密码来提交表单:
from flask_httpauth
import HTTPBasicAuth
from werkzeug.
security
import generate_password_hash
, check_password_hash
app
= Flask
( __name__
)
auth
= HTTPBasicAuth
(
)
users
=
{
"hr" : generate_password_hash
(
"secretpassword"
)
,
}
@ auth.
verify_password
def verify_password
( username
, password
) :
if username
in users:
return check_password_hash
( users.
get
( username
)
, password
)
return
False
@ app.
route
(
'/offboard'
, methods
=
[
'POST'
]
)
@ auth.
login_required
def offboard
(
) :
# ... as before …
指定用户名和密码以使请求成功:
~ $ curl -X POST \
-d
'{"employeeEmail": "shaun@anvil.works"}' \
-H
"Content-Type: application/json" \
http://localhost:
5000 /offboard
Unauthorized Access
ubuntu
@ ip-
172 -
31 -
17 -
9 :
~ $ curl -X POST -u hr:secretpassowrd \
-d
'{"employeeEmail": "shaun@anvil.works"}' \
-H
"Content-Type: application/json" \
http://localhost:
5000 /offboard
{
"remove_from_ldap.py" :
0
,
"revoke_github_permisisons.py" :
1
,
"update_org_chart.sh" :
0
}
如果人事部门乐于使用curl ,那么您将可以完成很多工作。 但是他们可能不会讲代码,因此在其上放一个前端。 为此,您必须设置一个Web服务器。
设置网络服务器
您需要Web服务器将静态内容呈现给用户。 “静态内容”是指最终由用户的Web浏览器使用的代码和数据,包括HTML,JavaScript和CSS以及图标和图像。
除非您希望整天离开工作站,并小心避免用力拉扯电源线,否则应将应用程序托管在公司的网络,私有云或其他安全的远程计算机上。 本示例将使用AWS EC2云服务器。
按照安装说明在远程计算机上安装Nginx:
sudo
apt-get update
sudo
apt-get install nginx
它已经可以将/ var / www / html中的任何内容提供给您,因此您可以将静态内容放入其中。
配置Nginx与Flask对话
配置它以了解Flask应用程序。 Nginx允许您配置有关URL匹配特定路径时如何托管内容的规则。 编写与确切路径/ offboard匹配的规则,并将请求转发到Flask:
# Inside the default server {} block in /etc/nginx/sites-enabled/default...
location =
/ offboard
{
proxy_pass http:
// 127.0.0.1:
5000 ;
}
现在重新启动Nginx。
假设您的EC2实例位于3.8.49.253。 在浏览器中转到http://3.8.49.253时,您会看到“欢迎使用Nginx!”。 页,并且如果您针对http://3.8.49.253/offboard发出卷曲请求,您将获得与以前相同的结果。 您的应用现已在线!
还有两件事要做:
- 购买域名并设置DNS记录( http://3.8.49.253/offboard不太漂亮!)。
- 设置SSL,以便对流量进行加密。 如果您是在线进行的,那么“加密”是一项出色的免费服务。
您可以自己弄清楚这些步骤。 它们如何工作在很大程度上取决于您的网络配置。
编写前端以触发脚本
现在是时候编写前端HR用来访问应用程序和启动脚本的时候了。
输入框和按钮HTML
前端将显示一个文本框,HR可以使用该文本框输入离职用户的电子邮件地址,并单击一个按钮将其提交到Flask应用程序。 这是用于此HTML:
<body>
<input type="email" id="email-box" placeholder="Enter employee email" />
<input type="button" id="send-button" onclick="makeRequest()" value="Run" />
<div id="status"></div>
</body>
空的<div>存储最近一次运行的结果。
将其保存到/var/www/html/offboarding/index.html ,然后浏览至http://3.8.49.253/offboarding 。 这是您得到的:
虽然还不是很漂亮,但是在结构上是正确的。
JavaScript和jQuery发出请求
请参阅HTML中的onclick =“ makeRequest()”以获取按钮? 它需要一个名为makeRequest的函数来使按钮在单击时调用。 此函数将数据发送到后端并处理响应。
要编写它,首先在HTML文件中添加一个<script>标记以导入jQuery ,这是一个非常有用JavaScript库,它将从您的页面提取电子邮件地址并发送请求:
<head>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
</head>
...
要使用jQuery发出HTTP POST请求:
var makeRequest
=
function makeRequest
(
)
{
// Make an asynchronous request to the back-end
$ .
ajax
(
{
type
:
"POST"
,
url
:
"/offboard"
,
data
: JSON.
stringify
(
{
"employeeEmail"
:
$
(
'#email-box'
)
[
0
] .
value
}
)
,
contentType
:
"application/json"
}
)
}
该请求是异步发出的,这意味着用户在等待响应时仍可以与该应用进行交互。 $ .ajax返回一个promise ,如果请求成功,它将运行传递给.done()方法的函数,如果请求失败,它将运行传递给.fail()方法的函数。 这些方法中的每一个都返回一个Promise,因此您可以像下面这样链接它们:
$ . ajax ( ... ) . done ( do_x ) . fail ( do_y )
$ . ajax ( ... ) . done ( do_x ) . fail ( do_y )
请求成功后,后端将返回脚本的退出代码,因此编写一个函数以针对表中的每个脚本名称显示退出代码:
function
(
data
)
{
// The process has finished, we can display the statuses.
var scriptStatuses
=
data
;
$
(
'#status'
) .
html
(
'<table style="width: 100%;" id="status-table"></table>'
)
;
for
( script
in scriptStatuses
)
{
$
(
'#status-table'
) .
append
(
'<tr><td>'
+ script
+
'</td><td>'
+ scriptStatuses
[ script
]
+
'</td></tr>'
)
;
}
}
$('#status')。html()获取具有ID 状态HTML文档对象模型(DOM)元素,并将HTML替换为您传入的字符串。
发生故障时,使用HTTP状态代码和响应正文触发警报,以便HR人员可以引用该警报,以在应用程序停止生产时向您发出警报。 完整的脚本如下所示:
var makeRequest
=
function makeRequest
(
)
{
// Make an asynchronous request to the back-end
var jqxhr
=
$ .
ajax
(
{
type
:
"POST"
,
url
:
"/offboard"
,
data
: JSON.
stringify
(
{
"employeeEmail"
:
$
(
'#email-box'
)
[
0
] .
value
}
)
,
contentType
:
"application/json"
}
) .
done
(
function
(
data
)
{
// The process has finished, we can display the statuses.
console.
log
(
data
)
;
var scriptStatuses
=
data
;
$
(
'#status'
) .
html
(
'<table style="width: 100%;" id="status-table"></table>'
)
;
for
( script
in scriptStatuses
)
{
$
(
'#status-table'
) .
append
(
'<tr><td>'
+ script
+
'</td><td>'
+ scriptStatuses
[ script
]
+
'</td></tr>'
)
;
}
}
)
.
fail
(
function
(
data
, textStatus
)
{
alert
(
"error: "
+
data
[
'statusText'
]
+
" "
+
data
[
'responseText'
]
)
;
}
)
}
将此脚本另存为/var/www/html/offboarding/js/offboarding.js并将其包含在HTML文件中:
<head>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="js/offboarding.js"></script>
</head>
...
现在,当您输入员工的电子邮件地址并点击Run时 ,脚本将运行并在表中提供其退出代码:
但是,它仍然很难看! 现在是解决该问题的时候了。
使它看起来不错
Bootstrap是一种以中立方式设计应用程序样式的好方法。 Bootstrap是一个CSS库(以及更多),它提供一个网格系统,使基于CSS的布局非常容易。 它也为您的应用程序提供了超级干净的外观。
Bootstrap的布局和样式
重组HTML,使事情最终出现在Bootstrap的行和列结构中的正确位置:列进入行,而行进入容器。 使用col , row和container CSS类将元素指定为列,行和容器,而card类为该行提供边框,使其看起来是独立的。
输入框放置在<form>内 ,文本框获取<label> 。 这是前端的最终HTML:
<head
>
<
link href
=
"https:///bootstrap/4.3.1/css/bootstrap.min.css" rel
=
"stylesheet" /
>
<
link href
=
"https:///font-awesome/4.7.0/css/font-awesome.min.css" rel
=
"stylesheet" /
>
<script src
=
"https://code.jquery.com/jquery-3.4.1.min.js"
> </script
>
<script src
=
"https:///bootstrap/4.3.1/js/bootstrap.min.js"
> </script
>
<script src
=
"js/offboarding.js"
> </script
>
</head
>
<body
>
<div class
=
"container" style
=
"padding-top: 40px"
>
<div class
=
"row card" style
=
"padding: 20px 0"
>
<div id
=
"email-input" class
=
"col"
>
<form
>
<div class
=
"form-group"
>
<label for
=
"email-box"
> Employee Email</label
>
<input type
=
"email" class
=
"form-control" id
=
"email-box" placeholder
=
"Enter employee email" /
>
</div
>
<input type
=
"button" class
=
"btn btn-primary" id
=
"send-button" onclick
=
"makeRequest()"
value
=
"Run" /
>
</form
>
<div id
=
"status"
> </div
>
</div
>
</div
>
</div
>
</body
>
现在是该应用的外观,这是一个巨大的改进。
添加状态图标
还有一件事:该应用程序报告状态为0表示成功,状态1表示失败,这通常会使不熟悉Unix的人感到困惑。 对于大多数人来说,如果它使用诸如对勾图标表示成功,而使用“ X”图标表示失败,则将更容易理解。
使用FontAwesome库获取选中标记和X图标。 就像从Bootstrap一样,只需从HTML <head>链接到库。 然后在JavaScript中修改循环以检查退出状态,如果状态为0则显示绿色,如果状态为其他,则显示红色X:
for
( script
in scriptStatuses
)
{
var fa_icon
= scriptStatuses
[ script
]
?
'fa-times'
:
'fa-check'
;
var icon_color
= scriptStatuses
[ script
]
?
'red'
:
'green'
;
$
(
'#status-table'
) .
append
(
'<tr><td>'
+ script
+
'</td><td><i class="fa '
+ fa_icon
+
'" style="color: '
+ icon_color
+
'"></i></td></tr>'
)
;
}
测试一下。 输入电子邮件地址,点击运行,然后…
美丽! 有用!
另外的选择
多么富有成效的一天! 您构建了一个使工作的重要部分自动化的应用程序。 唯一的缺点是您必须维护云实例,前端JavaScript和后端Python代码。
但是,如果您没有一整天的时间花在自动化或不想永远维护它们呢? 系统管理员必须使所有板块保持旋转,处理紧急请求,并应对越来越多的高优先级票务积压。 但是您可能可以在星期五下午偷偷进行30分钟的流程改进。 那段时间您能取得什么成就?
如果这是90年代中期,则可以在30分钟内在Visual Basic中构建某些东西。 但是您正在尝试构建一个Web应用程序,而不是桌面应用程序。 幸运的是,这里有帮助:您可以使用Anvil (一种基于开放源代码软件构建的服务)来使用Python编写应用程序-这次只需30分钟:
全面披露:Anvil是一项商业服务-尽管我们在本文中所做的一切都可以免费获得! 您可以在Anvil博客上找到有关构建此项目的分步指南 。
无论您走的是前进的道路-自行完成或使用诸如Anvil之类的工具,我们都希望您继续使所有事情自动化。 您要自动化哪种流程? 发表评论以激发您的系统管理员。
翻译自: https://opensource.com/article/19/9/web-apps-sysadmins
idea自动构建web项目