vault backup: 2026-04-16 23:51:17
This commit is contained in:
@@ -16,4 +16,273 @@
|
||||
- 域名(内网):`nos-gzdev.163nos.com`
|
||||
|
||||
## 文档
|
||||
- S3:https://sa.nie.netease.com/console/webconsole/idc/
|
||||
- S3:https://sa.nie.netease.com/console/webconsole/idc/
|
||||
|
||||
|
||||
# 垃圾电脑服务
|
||||
我现在想在局域网里的另一台Ubuntu电脑上部署Unreal Horde服务,存储 缓存以及管理各个worker、节点信息;本机性能强劲,作为worker进行具体工作。
|
||||
- 电脑ip:10.219.36.57
|
||||
- 用户名:netease
|
||||
- 密码:123
|
||||
|
||||
官方文档(UE5.5)
|
||||
- https://dev.epicgames.com/documentation/zh-cn/unreal-engine/horde-in-unreal-engine?application_version=5.5
|
||||
- Horde README.md https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Programs/Horde/README.md
|
||||
- [**Deploying Horde**](https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Programs/Horde/Docs/Deployment.md)
|
||||
- - 有关 Horde 的架构和组件的信息,以及部署它们的最佳实践。
|
||||
**受众:** IT、系统管理员、打算修改 Horde 的程序员。
|
||||
- [**Configuring and Operating Horde**](https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Programs/Horde/Docs/Config.md)
|
||||
- - 描述如何设置和管理 Horde。
|
||||
**受众:**构建/开发运营团队、管理员。
|
||||
- [**Horde Internals**](https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Programs/Horde/Docs/Internals.md)
|
||||
- - 描述如何构建和修改 Horde 及其架构。
|
||||
**受众:**希望扩展 Horde 的开发人员。
|
||||
- 视频
|
||||
- [Horde and Unreal Build Accelerator: Operating at Epic Scale](https://youtu.be/ZUlwqNbYWBQ?si=DgFvrvepK67v-iTi)
|
||||
|
||||
## 下载地址
|
||||
- 官方下载地址
|
||||
- 服务端:https://github.com/EpicGames/UnrealEngine/releases/download/5.5.0-release/UnrealHordeServer.msi
|
||||
|
||||
# 大致步骤
|
||||
1. 使用docker部署服务。
|
||||
2. 服务器配置。
|
||||
1. 默认端口Http 13340、Http 2 13342。
|
||||
1. 默认情况下,Horde配置为使用端口5000通过未加密的HTTP提供数据。在默认情况下,代理通过端口5002使用未加密的HTTP/2上的gRPC与Horde服务器通信。这些设置在服务器启动时显示在控制台上。
|
||||
2. [相关配置](https://dev.epicgames.com/documentation/zh-cn/unreal-engine/horde-orientation-for-unreal-engine?application_version=5.5)
|
||||
- [服务器配置](https://dev.epicgames.com/documentation/zh-cn/unreal-engine/horde-settings-for-unreal-engine?application_version=5.5#%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%AE%BE%E7%BD%AE)将配置该服务器与其他服务器的通信,定义静态参数等。它由与该服务器一同部署的 `Server.json` 文件驱动。
|
||||
- [完整配置参数清单](https://dev.epicgames.com/documentation/zh-cn/unreal-engine/horde-settings-for-unreal-engine?application_version=5.5#%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%AE%BE%E7%BD%AE)
|
||||
- [全局配置](https://dev.epicgames.com/documentation/zh-cn/unreal-engine/horde-schema-for-unreal-engine?application_version=5.5#globals)在部署后控制所有面向用户的元素,该配置存于名为 `Globals.json` 的文件中。设置好部署参数后,大多数配置都在此处完成。
|
||||
3. [验证相关配置](https://dev.epicgames.com/documentation/zh-cn/unreal-engine/horde-authentication-tutorial-for-unreal-engine?application_version=5.5)
|
||||
1. [[#OIDC身份验证]]
|
||||
3. 代理机配置。详见 http://10.219.103.35:13340/docs/Landing.md
|
||||
1. 配置文件位置:安装目录\Agent\Defaults\agent.json
|
||||
2.
|
||||
# 部署笔记
|
||||
|
||||
## 部署流程
|
||||
- [Horde服务器](https://dev.epicgames.com/documentation/zh-cn/unreal-engine/horde-server-for-unreal-engine?application_version=5.5)
|
||||
|
||||
# Perforce服务器
|
||||
ssl:inner02-commit.perforce.nie.netease.com:1667
|
||||
|
||||
# OIDC
|
||||
## Netease OIDC信息
|
||||
| | |
|
||||
| ------------- | ---------------------------------------------------------------- |
|
||||
| client id | 4884b03e951711f0ad370242ac120002 |
|
||||
| client secret | f2862b8c5ab24085ab0883d119b631604884b354951711f0ad370242ac120002 |
|
||||
## OIDC 参考代码
|
||||
```python
|
||||
#coding:UTF-8
|
||||
"""
|
||||
Requirements:
|
||||
1. Flask >= 0.10.1
|
||||
2. requests
|
||||
3. jwkest >= 1.1.7
|
||||
|
||||
Usage:
|
||||
python oidc_code_demo.py -H {listen_address} -p {listen_port}
|
||||
|
||||
Help:
|
||||
python oidc_code_demo.py -h
|
||||
"""
|
||||
import os
|
||||
import uuid
|
||||
from hashlib import md5
|
||||
import datetime
|
||||
from urllib import urlencode
|
||||
import json
|
||||
import requests
|
||||
from flask import Flask, request, jsonify, session, redirect
|
||||
|
||||
from jwkest.jwk import SYMKey
|
||||
from jwkest.jws import JWS
|
||||
from jwkest.jwk import load_jwks_from_url
|
||||
from jwkest.jws import NoSuitableSigningKeys
|
||||
|
||||
__revision__ = "0.01"
|
||||
__author__ = "chenxs@corp.netease.com"
|
||||
|
||||
OIDC_CLIENT_ID = ""
|
||||
OIDC_CLIENT_SECRET = ""
|
||||
OIDC_PROVIDER = "https://login.netease.com/connect"
|
||||
OIDC_AUTHORIZATION_SERVER = "https://login.netease.com/connect/authorize"
|
||||
OIDC_TOKEN_ENDPOINT = "https://login.netease.com/connect/token"
|
||||
OIDC_USERINFO_ENDPOINT = "https://login.netease.com/connect/userinfo"
|
||||
OIDC_SCOPE = "openid nickname email fullname dep title empno"
|
||||
OIDC_REDIRECT_URI = "https://127.0.0.1:5000/finish"
|
||||
OIDC_JWKS_URI = "https://login.netease.com/connect/jwks"
|
||||
OIDC_ALG = "HS256"
|
||||
|
||||
PYTHON_OIDC_DEMO = Flask(__name__)
|
||||
|
||||
@PYTHON_OIDC_DEMO.route("/", methods=['GET'])
|
||||
def index():
|
||||
"""index"""
|
||||
if 'username' in session:
|
||||
body = (
|
||||
u"</br><h2>OpenID Connect 鐧诲綍鎴愬姛銆<E5A79B></h2></br>"
|
||||
u"鎮ㄧ殑鐢ㄦ埛鍚嶆槸锛<EFBFBD>%s</br>"
|
||||
u"鎮ㄧ殑鍏ㄥ悕鏄細%s</br>"
|
||||
u"鎮ㄧ殑閭鏄細%s</br>"
|
||||
u"鎮ㄧ殑鑱屼綅鏄細%s</br>"
|
||||
u"鎮ㄧ殑閮ㄩ棬鏄細%s</br>"
|
||||
u"鎮ㄧ殑宸ュ彿鏄細%s</br>") % (
|
||||
session['username'], session.get('fullname', ''),
|
||||
session.get('email', ''), session.get('title', ''),
|
||||
session.get('dep', ''), session.get('empno', ''))
|
||||
body += u"<a href='/login'>鎴虫垜閲嶆柊鐧诲綍</a>"
|
||||
return body
|
||||
else:
|
||||
return u"<a href='/login'>鎴虫垜鐧诲綍</a>"
|
||||
|
||||
@PYTHON_OIDC_DEMO.route("/login", methods=['GET'])
|
||||
def login():
|
||||
"""AuthN Request"""
|
||||
session.clear()
|
||||
now = datetime.datetime.now().strftime("%s")
|
||||
session['uid'] = uuid.uuid4().hex
|
||||
session['state'] = session['uid']
|
||||
session['nonce'] = md5(session['uid'] + now).hexdigest()
|
||||
|
||||
authn_request_params = {
|
||||
'response_type': 'code',
|
||||
'client_id': OIDC_CLIENT_ID,
|
||||
'state': session['state'],
|
||||
'nonce': session['nonce'],
|
||||
'scope': OIDC_SCOPE,
|
||||
'redirect_uri': OIDC_REDIRECT_URI,
|
||||
#'prompt': 'login',
|
||||
'display': 'touch',
|
||||
}
|
||||
|
||||
redirect_url = "?".join([
|
||||
OIDC_AUTHORIZATION_SERVER, urlencode(authn_request_params)])
|
||||
|
||||
return redirect(redirect_url)
|
||||
|
||||
|
||||
def token_request(code):
|
||||
"""2. Token Request"""
|
||||
params = {
|
||||
'grant_type': 'authorization_code',
|
||||
'code': code,
|
||||
'redirect_uri': OIDC_REDIRECT_URI,
|
||||
'client_id': OIDC_CLIENT_ID,
|
||||
'client_secret': OIDC_CLIENT_SECRET,
|
||||
}
|
||||
_resp = requests.post(OIDC_TOKEN_ENDPOINT, data=params)
|
||||
return json.loads(_resp.text)
|
||||
|
||||
def id_token_verify(id_token, nonce=None):
|
||||
"""3. id token verify"""
|
||||
|
||||
now = int(datetime.datetime.now().strftime("%s"))
|
||||
if OIDC_ALG == "HS256":
|
||||
signed_keys = [SYMKey(key=OIDC_CLIENT_SECRET)]
|
||||
else:
|
||||
signed_keys = load_jwks_from_url(OIDC_JWKS_URI)
|
||||
|
||||
try:
|
||||
plain_id_token = JWS().verify_compact(id_token, signed_keys)
|
||||
except NoSuitableSigningKeys:
|
||||
# logger the id_token please
|
||||
return {'error': 'can not verify the id token'}
|
||||
|
||||
print "idtoken: %s" % plain_id_token
|
||||
if nonce:
|
||||
if (not plain_id_token.has_key('nonce')) or (
|
||||
plain_id_token['nonce'] != nonce):
|
||||
return {'error': 'id token nonce not correct'}
|
||||
if plain_id_token['iss'] != OIDC_PROVIDER:
|
||||
return {'error': 'id token iss not correct'}
|
||||
if plain_id_token['aud'] != OIDC_CLIENT_ID:
|
||||
return {'error': 'id token aud not correct'}
|
||||
if now >= int(plain_id_token['exp']):
|
||||
return {'error': 'id token expired'}
|
||||
|
||||
return {'id_token': plain_id_token}
|
||||
|
||||
|
||||
@PYTHON_OIDC_DEMO.route("/finish", methods=['GET'])
|
||||
def finish():
|
||||
"""
|
||||
1. AuthN Response
|
||||
2. Token Request
|
||||
3. id token verify
|
||||
4. userinfo request
|
||||
5. login user
|
||||
"""
|
||||
|
||||
# 1. AuthN Response
|
||||
try:
|
||||
code = request.args.get('code')
|
||||
if session['state']:
|
||||
state = request.args.get('state')
|
||||
if state != session['state']:
|
||||
return u"闈炴硶璇锋眰"
|
||||
except ValueError:
|
||||
return u"闈炴硶璇锋眰"
|
||||
# 2. Token Request
|
||||
token = token_request(code)
|
||||
print "token: %s" % token
|
||||
if token.has_key('error'):
|
||||
return u"鍑洪敊浜嗭細%s" % str(token)
|
||||
# 3. id token verify
|
||||
id_token_verified = id_token_verify(token['id_token'])
|
||||
if id_token_verified.has_key('error'):
|
||||
return id_token_verified['error']
|
||||
else:
|
||||
id_token = id_token_verified['id_token']
|
||||
|
||||
print "id_token: %s" % id_token
|
||||
|
||||
# 4. userinfo request
|
||||
_req_session = requests.Session()
|
||||
_req_session.headers.update({
|
||||
"Authorization": "Bearer %s" % token['access_token']})
|
||||
userinfo_req = _req_session.get(OIDC_USERINFO_ENDPOINT)
|
||||
userinfo = json.loads(userinfo_req.text)
|
||||
# login the user
|
||||
session['username'] = userinfo['nickname']
|
||||
session['email'] = userinfo['email']
|
||||
session['title'] = userinfo.get('title', '')
|
||||
session['empno'] = userinfo.get('empno', '')
|
||||
session['dep'] = userinfo.get('dep', '')
|
||||
session['fullname'] = userinfo.get('fullname', '')
|
||||
return redirect("/")
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(
|
||||
usage='%(prog)s [options]', version='%(prog)s ' + str(__revision__))
|
||||
parser.add_argument(
|
||||
'-H', '--host', dest='host', type=str,
|
||||
help="Specify listening adress, default is 127.0.0.1")
|
||||
parser.add_argument(
|
||||
'-p', '--port', dest='port', type=int,
|
||||
help="Specify listening port, default is 5000")
|
||||
parser.add_argument(
|
||||
'-c', '--client_id', dest='client_id', type=str,
|
||||
help="oidc client_id is required.")
|
||||
parser.add_argument(
|
||||
'-s', '--client_secret', dest='client_secret', type=str,
|
||||
help="oidc client_secret is required.")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
host = args.host or '127.0.0.1'
|
||||
port = args.port or 5000
|
||||
OIDC_REDIRECT_URI = "http://%s:%s/finish" % (host, port)
|
||||
OIDC_CLIENT_ID = args.client_id
|
||||
OIDC_CLIENT_SECRET = args.client_secret
|
||||
if not OIDC_CLIENT_ID or not OIDC_CLIENT_SECRET:
|
||||
parser.print_help()
|
||||
parser.exit()
|
||||
|
||||
PYTHON_OIDC_DEMO.secret_key = "this is a random secret"
|
||||
PYTHON_OIDC_DEMO.debug = True
|
||||
PYTHON_OIDC_DEMO.run(host=host, port=port)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user