SCFCLI和VSCode的插件很早之前就有了,也有很多用戶(hù)在使用這兩個(gè)工具, 使用它們可以通過(guò)已經(jīng)寫(xiě)的Yaml直接把函數(shù)部署到線(xiàn)上,非常方便艺智。但是眼尖的小伙伴已經(jīng)發(fā)現(xiàn)這樣一件事:SCFCLI和VSCode插件貌似很久都沒(méi)更新了,而且云函數(shù)的小伙伴在極力推動(dòng)大家使用Serverless Framework圾亏∈穑可以看到SCFCLI在6月份的時(shí)候更新頻繁,而現(xiàn)在志鹃,更新緩慢夭问。
同時(shí),細(xì)心的小伙伴還發(fā)現(xiàn)了弄跌,Serverless Framework貌似比SCFCLI好用凹缀取!因?yàn)樗粌H僅可以部署函數(shù)铛只,還可以部署APIGW埠胖,COS,CDN......最主要淳玩,通過(guò)Serverless Frameworek還可以快速的把常用的框架直撤,例如Express、Flask蜕着、Django.....等直接部署到云函數(shù)上谋竖,這是多方便的一件事情啊承匣!
就問(wèn)還在用SCFCLI的小伙伴蓖乘,你們酸沒(méi)酸?
有的小伙伴在躍躍欲試之后韧骗,終于下定決心嘉抒,將SCFCLI放棄掉,開(kāi)始使用Serverless Framework袍暴,那么問(wèn)題來(lái)了些侍,這兩個(gè)東西的Yaml寫(xiě)的不一樣,是完全不一樣政模,那么應(yīng)該如何把已有的SCFCLI/VSCode插件的Yaml快速轉(zhuǎn)換成為Serverless Framework的Yaml呢岗宣?
下面就是幾個(gè)簡(jiǎn)單的實(shí)現(xiàn)方法:
通過(guò)網(wǎng)頁(yè)進(jìn)行轉(zhuǎn)換
作為社區(qū)愛(ài)好者,我必然要提供一個(gè)簡(jiǎn)單的網(wǎng)頁(yè)淋样,來(lái)做這個(gè)事情:
http://serverless.0duzhan.com/app/scf_2_serverless/
通過(guò)這個(gè)網(wǎng)址耗式,你只需要輸入基于SCFCLI的Yaml,就可以快速轉(zhuǎn)換:
轉(zhuǎn)換結(jié)果是可以同時(shí)生成Component的Yaml和Plugin的Yaml
通過(guò)接口自主轉(zhuǎn)換
接口地址:
- Component:http://service-8d3fi753-1256773370.bj.apigw.tencentcs.com/release/scf_2_serverless/components/
- Plugin:http://service-8d3fi753-1256773370.bj.apigw.tencentcs.com/release/scf_2_serverless/plugin/
輸入?yún)?shù):yaml,字符串類(lèi)型纽什,就是之前SCFCLI/VSCODE插件的Yaml內(nèi)容
輸出參數(shù):error措嵌,布爾類(lèi)型躲叼,是否出錯(cuò)芦缰;result,字符串類(lèi)型枫慷,結(jié)果(error為true让蕾,此處輸出錯(cuò)誤信息,為false時(shí)輸出新的yaml結(jié)果)
以Python語(yǔ)言為例或听,將原有的Yaml轉(zhuǎn)換成為Component的Yaml可以這樣操作:
import urllib.request
import json
with open("template.yaml", 'r') as f:
yamlData = f.read()
url = "http://service-8d3fi753-1256773370.bj.apigw.tencentcs.com/release/scf_2_serverless/components/"
data = {
"yaml": yamlData
}
yamlResult = json.loads(urllib.request.urlopen(urllib.request.Request(url=url, data=json.dumps(data).encode("utf-8"))).read().decode("utf-8"))
print(yamlResult)
with open("output.yaml", "w") as f:
f.write(yamlResult['result'])
這樣就可以把已有的SCFCLI Yaml轉(zhuǎn)換成Serverless Component的Yaml了探孝,Plugin的轉(zhuǎn)換方法同理,只需要更換一個(gè)一下url地址就好了誉裆。
自己寫(xiě)本地腳本來(lái)轉(zhuǎn)
def getBaseFunctionComponents(functionInformation, functionName=None, tempInputs=None):
tempInputs = tempInputs if tempInputs else {}
if functionName:
tempInputs["name"] = functionName
if isinstance(functionInformation, dict):
for eveFunctionKey, eveFunctionValue in functionInformation.items():
if eveFunctionKey not in ["Events", "Environment", "VpcConfig", "Type", "Role"]:
tempKey = str.lower(eveFunctionKey[0]) + eveFunctionKey[1:]
tempInputs[tempKey] = eveFunctionValue
else:
if eveFunctionKey == "Environment":
if eveFunctionValue and "Variables" in eveFunctionValue:
tempEnvironment = {
"variables": eveFunctionValue["Variables"]
}
tempInputs["environment"] = tempEnvironment
elif eveFunctionKey == "VpcConfig":
tempVpcConfig = {}
if eveFunctionValue and "SubnetId" in eveFunctionValue:
tempSubnetId = eveFunctionValue["SubnetId"]
tempVpcConfig["subnetId"] = tempSubnetId
if eveFunctionValue and "VpcId" in eveFunctionValue:
tempVpcId = eveFunctionValue["VpcId"]
tempVpcConfig["vpcId"] = tempVpcId
tempInputs["vpcConfig"] = tempVpcConfig
elif eveFunctionKey == "Events":
tempEvents = []
if isinstance(eveFunctionValue, dict):
for eveEventKey, eveEventValue in eveFunctionValue.items():
if isinstance(eveEventValue["Properties"], dict):
tempEvent = {}
if eveEventValue["Type"] == "APIGW":
tempEvent['apigw'] = {
"name": eveEventKey,
"parameters": {}
}
tempParameter = {}
tempEndpoints = {"path": "/" + functionName}
for eveParameterKey, eveParameterValue in eveEventValue["Properties"].items():
if eveParameterKey == "StageName":
tempParameter["environment"] = eveParameterValue
elif eveParameterKey == "ServiceId" and eveParameterValue:
tempParameter["serviceId"] = eveParameterValue
elif eveParameterKey == "HttpMethod":
tempEndpoints["method"] = eveParameterValue
elif eveParameterKey == "IntegratedResponse":
tempEndpoints["function"] = {"isIntegratedResponse": eveParameterValue}
tempParameter["endpoints"] = [tempEndpoints, ]
tempEvent['apigw']["parameters"] = tempParameter
elif eveEventValue["Type"] == "COS":
tempEvent['cos'] = {
"name": eveEventKey,
"parameters": {}
}
tempParameter = {}
for eveParameterKey, eveParameterValue in eveEventValue["Properties"].items():
if eveParameterKey == "Filter":
tempFilter = {}
for eveFilterKey, eveFilterValue in eveParameterValue.items():
tempKey = str.lower(eveFilterKey[0]) + eveFilterKey[1:]
tempFilter[tempKey] = eveFilterValue
tempParameter["filter"] = tempFilter
else:
tempKey = str.lower(eveParameterKey[0]) + eveParameterKey[1:]
tempParameter[tempKey] = eveParameterValue
tempEvent['cos']["parameters"] = tempParameter
elif eveEventValue["Type"] == "Timer":
tempEvent['timer'] = {
"name": eveEventKey,
"parameters": {}
}
tempParameter = {}
for eveParameterKey, eveParameterValue in eveEventValue["Properties"].items():
tempKey = str.lower(eveParameterKey[0]) + eveParameterKey[1:]
tempParameter[tempKey] = eveParameterValue
tempEvent['timer']["parameters"] = tempParameter
elif eveEventValue["Type"] == "CMQ":
tempEvent['cmq'] = {
"name": eveEventKey,
"parameters": {}
}
tempParameter = {}
for eveParameterKey, eveParameterValue in eveEventValue["Properties"].items():
tempKey = str.lower(eveParameterKey[0]) + eveParameterKey[1:]
tempParameter[tempKey] = eveParameterValue
tempEvent['cmq']["parameters"] = tempParameter
elif eveEventValue["Type"] == "CKafka":
tempEvent['ckafka'] = {
"name": eveEventKey,
"parameters": {}
}
tempParameter = {}
for eveParameterKey, eveParameterValue in eveEventValue["Properties"].items():
tempKey = str.lower(eveParameterKey[0]) + eveParameterKey[1:]
tempParameter[tempKey] = eveParameterValue
tempEvent['ckafka']["parameters"] = tempParameter
tempEvents.append(tempEvent)
if tempEvents:
tempInputs["events"] = tempEvents
return tempInputs
def getFunctionComponents(functionName, function, tempInputs):
isFunction = False
if isinstance(function, dict):
for eveKey, eveValue in function.items():
if eveKey == "Type" and eveValue == "TencentCloud::Serverless::Function":
isFunction = True
if isFunction:
for eveKey, eveValue in function.items():
if eveKey == "Type" and eveValue == "TencentCloud::Serverless::Function":
continue
else:
tempInputs = getBaseFunctionComponents(eveValue, functionName, tempInputs)
serverlessPluginYaml = {
"component": '@serverless/tencent-scf',
"inputs": tempInputs
}
return serverlessPluginYaml
else:
return False
def getEventPlugin(eventType, eventName, eventSource, deepList=[]):
tempEvent = {}
tempEvent[eventType] = {
"name": eventName,
"parameters": {}
}
tempParameter = {}
for eveParameterKey, eveParameterValue in eventSource["Properties"].items():
tempKey = str.lower(eveParameterKey[0]) + eveParameterKey[1:]
if deepList and eveParameterKey in deepList:
tempDeepData = {}
for eveFilterKey, eveFilterValue in eveParameterValue.items():
tempThisKey = str.lower(eveFilterKey[0]) + eveFilterKey[1:]
tempDeepData[tempThisKey] = eveFilterValue
tempParameter[tempKey] = tempDeepData
continue
tempParameter[tempKey] = eveParameterValue
tempEvent[eventType]["parameters"] = tempParameter
return tempEvent
def getBaseFunctionPlugin(functionInformation, functionName=None, tempInputs=None):
tempInputs = tempInputs if tempInputs else {}
if functionName:
tempInputs["name"] = functionName
if isinstance(functionInformation, dict):
for eveFunctionKey, eveFunctionValue in functionInformation.items():
if eveFunctionKey not in ["Events", "Environment", "VpcConfig", "Type", "Role"]:
tempKey = str.lower(eveFunctionKey[0]) + eveFunctionKey[1:]
tempInputs[tempKey] = eveFunctionValue
else:
if eveFunctionKey == "Environment":
if eveFunctionValue and "Variables" in eveFunctionValue:
tempEnvironment = {
"variables": eveFunctionValue["Variables"]
}
tempInputs["environment"] = tempEnvironment
elif eveFunctionKey == "VpcConfig":
tempVpcConfig = {}
if eveFunctionValue and "SubnetId" in eveFunctionValue:
tempSubnetId = eveFunctionValue["SubnetId"]
tempVpcConfig["subnetId"] = tempSubnetId
if eveFunctionValue and "VpcId" in eveFunctionValue:
tempVpcId = eveFunctionValue["VpcId"]
tempVpcConfig["vpcId"] = tempVpcId
tempInputs["vpcConfig"] = tempVpcConfig
elif eveFunctionKey == "Events":
tempEvents = []
if isinstance(eveFunctionValue, dict):
for eveEventKey, eveEventValue in eveFunctionValue.items():
if isinstance(eveEventValue["Properties"], dict):
tempEvent = {}
if eveEventValue["Type"] == "APIGW":
tempEvent = getEventPlugin("apigw", eveEventKey, eveEventValue)
elif eveEventValue["Type"] == "COS":
tempEvent = getEventPlugin("cos", eveEventKey, eveEventValue, ["Filter"])
elif eveEventValue["Type"] == "Timer":
tempEvent = getEventPlugin("timer", eveEventKey, eveEventValue)
elif eveEventValue["Type"] == "CMQ":
tempEvent['cmq'] = getEventPlugin("cmq", eveEventKey, eveEventValue)
elif eveEventValue["Type"] == "CKafka":
tempEvent = getEventPlugin("ckafka", eveEventKey, eveEventValue)
tempEvents.append(tempEvent)
if tempEvents:
tempInputs["events"] = tempEvents
return tempInputs
def getFunctionPlugin(functionName, function, tempInputs):
isFunction = False
if isinstance(function, dict):
for eveKey, eveValue in function.items():
if eveKey == "Type" and eveValue == "TencentCloud::Serverless::Function":
isFunction = True
if isFunction:
for eveKey, eveValue in function.items():
if eveKey == "Type" and eveValue == "TencentCloud::Serverless::Function":
continue
else:
return getBaseFunctionPlugin(eveValue, functionName, tempInputs)
else:
return False
def doComponents(scfYaml):
try:
yamlData = yaml.load(scfYaml)
functions = {}
if "Globals" in yamlData:
inputs = getBaseFunctionComponents(yamlData["Globals"]["Function"])
if isinstance(yamlData['Resources'], dict):
for eveKey, eveValue in yamlData['Resources'].items():
for eveNamespaceKey, eveNamespaceValue in eveValue.items():
tempInputs = inputs.copy()
if eveNamespaceKey == "Type" and eveNamespaceValue == "TencentCloud::Serverless::Namespace":
continue
tempFunction = getFunctionComponents(eveNamespaceKey, eveNamespaceValue, tempInputs)
if tempFunction:
functions[eveNamespaceKey] = tempFunction
return {
"error": False,
"result": yaml.safe_dump(functions)
}
except:
return {
"error": True,
"result": "Scf Yaml未能正常轉(zhuǎn)換為Serverless Component Yaml"
}
def doPlugin(scfYaml):
try:
yamlData = yaml.load(scfYaml)
# 獲取Provider
print("獲取Provider")
if "Globals" in yamlData:
provider = getBaseFunctionPlugin(yamlData["Globals"]["Function"])
provider["name"] = "tencent"
provider["credentials"] = "~/credentials"
# 獲取service
print("獲取Service")
service = "Tencent-Serverless-Framework"
# 獲取插件
print("獲取Plugin")
plugin = ["serverless-tencent-scf"]
# 獲取函數(shù)
print("獲取Function")
functions = {}
if isinstance(yamlData['Resources'], dict):
for eveKey, eveValue in yamlData['Resources'].items():
for eveNamespaceKey, eveNamespaceValue in eveValue.items():
tempInputs = {}
if eveNamespaceKey == "Type" and eveNamespaceValue == "TencentCloud::Serverless::Namespace":
continue
tempFunction = getFunctionPlugin(eveNamespaceKey, eveNamespaceValue, tempInputs)
if tempFunction:
functions[eveNamespaceKey] = tempFunction
serverlessJson = {
"service": service,
"provider": provider,
"plugins": plugin,
"functions": functions
}
return {
"error": False,
"result": yaml.safe_dump(serverlessJson)
}
except Exception as e:
print(e)
return {
"error": True,
"result": "Scf Yaml未能正常轉(zhuǎn)換為Serverless Plugin Yaml"
}
是的顿颅,就是這么粗暴,上來(lái)就扔代碼足丢。
使用方法很簡(jiǎn)單粱腻,如果是轉(zhuǎn)Plugin:
pluginYaml = doPlugin(scfYaml)
如果是轉(zhuǎn)Component:
componentYaml = doComponent(scfYaml)
代碼不是很好看,但是可以用斩跌,所以各位大佬輕噴就好绍些。另外代碼開(kāi)源了,可以參考:https://github.com/anycodes/ServerlessPractice/tree/master/scf_2_serverless