SCFCLI和VSCode的插件很早之前就有了,也有很多用戶在使用這兩個工具, 使用它們可以通過已經寫的Yaml直接把函數部署到線上,非常方便。但是眼尖的小夥伴已經發現這樣一件事:SCFCLI和VSCode插件貌似很久都沒更新了,而且雲函數的小夥伴在極力推動大家使用Serverless Framework。可以看到SCFCLI在6月份的時候更新頻繁,而現在,更新緩慢。
同時,細心的小夥伴還發現了,Serverless Framework貌似比SCFCLI好用啊!因為它不僅僅可以部署函數,還可以部署APIGW,COS,CDN……最主要,通過Serverless Frameworek還可以快速的把常用的框架,例如Express、Flask、Django…..等直接部署到雲函數上,這是多方便的一件事情啊!
就問還在用SCFCLI的小夥伴,你們酸沒酸?
有的小夥伴在躍躍欲試之後,終於下定決心,將SCFCLI放棄掉,開始使用Serverless Framework,那麼問題來了,這兩個東西的Yaml寫的不一樣,是完全不一樣,那麼應該如何把已有的SCFCLI/VSCode插件的Yaml快速轉換成為Serverless Framework的Yaml呢?
下面就是幾個簡單的實現方法:
通過網頁進行轉換
作為社區愛好者,我必然要提供一個簡單的網頁,來做這個事情:
http://serverless.0duzhan.com/app/scf_2_serverless/
通過這個網址,你只需要輸入基於SCFCLI的Yaml,就可以快速轉換:
轉換結果是可以同時生成Component的Yaml和Plugin的Yaml
通過接口自主轉換
接口地址:
- 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/
輸入參數:yaml,字符串類型,就是之前SCFCLI/VSCODE插件的Yaml內容
輸出參數:error,布爾類型,是否出錯;result,字符串類型,結果(error為true,此處輸出錯誤信息,為false時輸出新的yaml結果)
以Python語言為例,將原有的Yaml轉換成為Component的Yaml可以這樣操作:
<code>import urllib.requestimport jsonwith 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'])/<code>
這樣就可以把已有的SCFCLI Yaml轉換成Serverless Component的Yaml了,Plugin的轉換方法同理,只需要更換一個一下url地址就好了。
自己寫本地腳本來轉
<code>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 tempInputsdef 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 Falsedef 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 tempEventdef 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 tempInputsdef 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 Falsedef 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未能正常轉換為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"] # 獲取函數 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未能正常轉換為Serverless Plugin Yaml" }/<code>
是的,就是這麼粗暴,上來就扔代碼。
使用方法很簡單,如果是轉Plugin:
<code>pluginYaml = doPlugin(scfYaml)/<code>
如果是轉Component:
<code>componentYaml = doComponent(scfYaml)/<code>
代碼不是很好看,但是可以用,所以各位大佬輕噴就好。另外代碼開源了,可以參考:https://github.com/anycodes/ServerlessPractice/tree/master/scf_2_serverless
閱讀更多 GoServerless 的文章