Directory
- UI interface
- Portal Services
- Admin Service
- Summarize
1. UI interface
2. Portal Services
When we click on the Publish button above, the interface of the portal is of course called. The specific code is as follows:
/** * Full Volume release * @param appId SampleApp * @param env DEV * @param clustername default * @param namespacename APPL ication * @param branchname Branch/Grayscale name * @param deletebranch true * @param model {"Releasetitle": "20180716220550-gray-r Elease-merge-to-master "," releasecomment ":" "," Isemergencypublish ": false} * @return */@PreAuthorize (value =" @permiss Ionvalidator.hasreleasenamespacepermission (#appId, #namespaceName) ") @RequestMapping (value ="/apps/{appid}/envs/{ Env}/clusters/{clustername}/namespaces/{namespacename}/branches/{branchname}/merge ", method = RequestMethod.POST) Public releasedto Merge (@PathVariable string appId, @PathVariable string env, @PathVariable Strin g clustername, @PathVariable string namespacename, @PathVariable string branchname, @RequestParam (value = "Deletebranch", DefaultValue = "true"), Boolean deletebranch, @RequestBody Namespacerelea Semodel model) {//If it is an emergency release, but the environment does not allow tightUrgent release, throw exception if (Model.isemergencypublish () &&!portalconfig.isemergencypublishallowed (env.fromstring (ENV))) { throw new Badrequestexception (String.Format ("env:%s is not supported emergency publish Now", Env)); }//Merge major and grayscale versions, get a release dto releasedto createdrelease = Namespacebranchservice.merge (AppId, env.valueof (ENV), Cluste Rname, NamespaceName, Branchname, Model.getreleasetitle (), MoD El.getreleasecomment (), Model.isemergencypublish (), Deletebran CH); Configpublishevent event = configpublishevent.instance (); Event.withappid (appId). Withcluster (clustername). Withnamespace (NamespaceName). Withreleaseid (created Release.getid ()). Setmergeevent (True). SETENV (Env.valueof (ENV)); Publisher.publishevent (event);//Send mail return createdrelease; }
The interface does not have much responsibility: whether it meets the data validation of the emergency release, invokes the Service, and publishes the Configure publish event (sending the message).
Look at the process of invoking a Service called merge, which is actually merging grayscale and major versions of the configuration. The code is as follows:
public ReleaseDTO merge(String appId, Env env, String clusterName, String namespaceName, String branchName, String title, String comment, boolean isEmergencyPublish, boolean deleteBranch) { // 计算 changeSets ItemChangeSets changeSets = calculateBranchChangeSet(appId, env, clusterName, namespaceName, branchName); // 调用 admin 服务 ReleaseDTO mergedResult = releaseService.updateAndPublish(appId, env, clusterName, namespaceName, title, comment, branchName, isEmergencyPublish, deleteBranch, changeSets); Tracer.logEvent(TracerEventType.MERGE_GRAY_RELEASE, String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName)); return mergedResult; }
2 things are done: Calculate the Change collection and invoke the Admin service. It is clear that the calculation of the change is very important for protal.
The Calculatebranchchangeset method mainly merges grayscale configuration and major version configuration.
Code:
Private Itemchangesets Calculatebranchchangeset (string appId, env env, string clustername, String namespacename, String branchname) {Namespacebo parentnamespace = Namespaceservice.loadnamespacebo (AppId, env, clustername, namespacename);//Parent version namespace if (Parentnamespace = = null) {throw new badrequestexception ("Base namespace not existed"); } if (parentnamespace.getitemmodifiedcnt () > 0) {throw new Badrequestexception ("Merge operation failed. Because Master has modified items "); } list<itemdto> Masteritems = Itemservice.finditems (appId, env, clustername, namespacename);//main version Items List< itemdto> Branchitems = Itemservice.finditems (appId, env, Branchname, namespacename);//Sub-version items Itemchangesets Chang Esets = Itemscomparator.compareignoreblankandcommentitem (Parentnamespace.getbaseinfo (). GetId (), Masteritems, Branchitems);//Get CHangeset Changesets.setdeleteitems (Collections.emptylist ());//Prevent accidental deletion, EMM, grayscale content is not the full amount, so the above calculation some problems, and there is no deletion function. So this place can be empty. Changesets.setdatachangelastmodifiedby (Userinfoholder.getuser (). GetUserId ()); return changesets;}
Steps:
- Gets the namespace details for the major version for data validation, ID assignment.
- To get all the item configurations for the major version, and then get all the item configurations for the grayscale version, note that the grayscale version of item has only its own new and modified configuration, not the full amount (which will cause a strange phenomenon later).
- Compare the two differences and get the change collection.
- Set DeleteList to empty--strange phenomenon (
灰度的内容并不是全量的,因此上面的计算有些问题,并且目前没有删除功能。所以这里可以置空, 并且防止误删除 ).
- Set the modifier.
It is important to note how the calculation difference is calculated and why there is an empty deleteItem operation behind it.
I'm not going to stick to the whole method. Code that has an impact on the delete operation:
/** 比较,忽略空格,返回一个改变的 items */public ItemChangeSets compareIgnoreBlankAndCommentItem(long baseNamespaceId, List<ItemDTO> baseItems, List<ItemDTO> targetItems){ // 忽略新增/修改 item 代码...... // 处理删除,但这个逻辑似乎不对. 不过此类不知道数据来源,工具类没有问题. for (ItemDTO item: baseItems){// 主版本 String key = item.getKey(); ItemDTO targetItem = targetItemMap.get(key); if(targetItem == null){//delete// 如果灰度版本里没有,说明删除了. changeSets.addDeleteItem(item);// 添加进删除集合 } } return changeSets;}
You can see, in this code, the loop major version, one by one grayscale version, if not in the grayscale version, added to the Delete collection, and we know that the grayscale version of the item only modified and added, at this time, will result in the accidental deletion.
However, the calculation of this tool class is not a problem, the problem is the integrity of the outer data.
So you need to make a patch outside:changeSets.setDeleteItems(Collections.emptyList());
OK, after calculating the ChangeSet, the Admin service is called, and the ChangeSet is passed over, and then a release object is returned, indicating that the publication was successful and the event was published.
Before you analyze admin, summarize the protal process:
3. Admin Service
From the portal code, you can see that the admin Updateandpublish method interface is invoked to see this interface:
Position:com.ctrip.framework.apollo.adminservice.controller.ReleaseController.java
The code is as follows:
@Transactional @RequestMapping (Path = "/apps/{appid}/clusters/{clustername}/namespaces/{namespacename}/ Updateandpublish ", method = requestmethod.post) public releasedto updateandpublish (@PathVariable (" AppId ") String appId ,//Application name @PathVariable ("clustername") String clustername,//Cluster @PathVariable ("NamespaceName") String namespacename,//major version name @RequestParam ("Releasename") String releasename,//Publish name @RequestParam ("Branchname") string branchname,//grayscale name Clus ter @RequestParam (value = "Deletebranch", DefaultValue = "true"), Boolean deletebranch, Whether to delete the grayscale @RequestParam (name = "Releasecomment", required = False) String Releasecomme nt,//comment @RequestParam (name = "Isemergencypublish", DefaultValue = "false") Boolean is emergencypublish,//whether the emergency release @RequestBody itemchangesets changesets) {//This is the portal from Namespace Namespace = NA Mespaceservice.findone (AppId, clustername, namespacename);//Find Branch if (namespace = = null) {throw new Notfoundexcep tion (String.Format ("Could not find namespace for%s%s", AppId, ClusterN Ame, NamespaceName)); }//merge changes and publish release release = Releaseservice.mergebranchchangesetsandrelease (namespace, Branchname, Releasename, Releasecomment, Isemergencypublish, changesets); Whether to delete the branch if (deletebranch) {namespacebranchservice.deletebranch (appId, ClusterName, NamespaceName, Branchname, Namespacebranchstatus.merged, Changesets.getdatachangelastmodifiedby ()); }//Save publish message to Database Messagesender.sendmessage (Releasemessagekeygenerator.generate (AppId, ClusterName, NamespaceName), TOPICS.APOLLO_RELEASE_TOPIC); Return Beanutils.transfrom (Releasedto.class, release); }
This interface accepts portal calls, and the interesting point is that the changeSet here are computed by the portal, not by the admin itself.
Then, the controller layer is simpler, the data is verified, the Service is called, and the message is sent.
Of course mainly look at Service.
Mainly Releaseservice's Mergebranchchangesetsandrelease method, look at the name, a lot of tasks: merging branches to modify the collection, and publish.
The code is as follows:
@Transactionalpublic Release mergebranchchangesetsandrelease (Namespace Namespace, String branchname, String Releasename, String releasecomment, Boolean isemergencypublish, Itemchangesets changesets) {//Check lock Checklock (namespace, Isemergencypublish, ChangeSet S.getdatachangelastmodifiedby ()); Updated Item Itemsetservice.updateset (namespace, changesets); Find the latest released release release branchrelease = Findlatestactiverelease (Namespace.getappid (), Branchname, namespace. Getn Amespacename ()); Release Id Long Branchreleaseid = Branchrelease = = null? 0:branchrelease.getid (); Find all the Item (just updated) map<string of the current namespace, string> Operatenamespaceitems = Getnamespaceitems (namespace); map<string, object> operationcontext = Maps.newhashmap (); Constructs the operation context sourcebranch= grayscale name basereleaseid= The latest ReleaseID isemergencypublish= is an emergency release for building a release history operationcontext.put ( Releaseoperationcontext.sOurce_branch, Branchname); Operationcontext.put (releaseoperationcontext.base_release_id, Branchreleaseid); Operationcontext.put (Releaseoperationcontext.is_emergency_publish, isemergencypublish); Releasehistory Audit Main version return Masterrelease (namespace, Releasename, Releasecomment, Operatenamespaceitems, Changesets.getdatachangelastmodifiedby (),//grayscale merge back to Main branch release Releaseop Eration. Gray_release_merge_to_master, OperationContext);}
The code is simple, step:
- Check the lock, as with the general release, judging whether the modifier and the publisher are not the same person.
- The item is updated according to the changesets passed by the Portal.
- Find the latest released release (the context in which the release history was built).
- Release the major version.
Among them, the Updateset method is more important, to see how he updated the item.
The method is long, in short, the ChangeSet content is saved to the main version of the namespace.
@Transactionalpublic itemchangesets Updateset (String appId, string clustername, string name Spacename, Itemchangesets ChangeSet) {///last person to change the data String operator = Changeset.getdatachangelastmodifiedby (); Change data details Configchangecontentbuilder Configchangecontentbuilder = new Configchangecontentbuilder (); If you create a new if (! Collectionutils.isempty (Changeset.getcreateitems ())) {//Loop for (Itemdto Item:changeSet.getCreateItems ()) { Convert Item entity = Beanutils.transfrom (Item.class, item); Entity.setdatachangecreatedby (operator); Entity.setdatachangelastmodifiedby (operator); Save item to database Item Createditem = Itemservice.save (entity); Save to builder CreateItems list Configchangecontentbuilder.createitem (Createditem); }//Last recorded audit Auditservice.audit ("Itemset", NULL, Audit.OP.INSERT, operator); }//If there are modified data if (! Collectionutils.isempty (Changeset.getupdateitems ())) {for (Itemdto item:changesEt.getupdateitems ()) {//convert and look for item entity = Beanutils.transfrom (Item.class, item); Item Manageditem = Itemservice.findone (Entity.getid ()); There is no throw exception if (Manageditem = = null) {throw new Notfoundexception (String.Format ("Item not found. key=%s) ", Entity.getkey ())); }//Previous data Item Beforeupdateitem = Beanutils.transfrom (Item.class, Manageditem); Protect. Only Value,comment,lastmodifiedby,linenum can modified//updates the previous data content Manageditem.setvalue (Entity.getvalue ()); Manageditem.setcomment (Entity.getcomment ()); Manageditem.setlinenum (Entity.getlinenum ()); Manageditem.setdatachangelastmodifiedby (operator); Update Item Updateditem = Itemservice.update (Manageditem); Update Builder in Value Configchangecontentbuilder.updateitem (Beforeupdateitem, Updateditem); }//FINAL audit itemset auditservice.audit ("Itemset", NULL, Audit.OP.UPDATE, operator); }//If there are deleted if (! Collectionutils.isempty (changeSet.getdeleteitems ())) {for (Itemdto Item:changeSet.getDeleteItems ()) {//database deleted item Deleteditem = Itemse Rvice.delete (Item.getid (), operator); Add to Builder in Configchangecontentbuilder.deleteitem (Deleteditem); }//Audit Auditservice.audit ("Itemset", NULL, Audit.OP.DELETE, operator); }//If the builder has content if (Configchangecontentbuilder.hascontent ()) {//Create commit record Createcommit (AppId, clustername, name Spacename, Configchangecontentbuilder.build (),//build into JSON save Changeset.getdatachangelastmod Ifiedby ()); } return ChangeSet;}
After the successful update of the ITME, you can make the final release, the release is very simple, do not start speaking.
Then look at delete grayscale, which is to be deleted by default.
Steps:
- Find the latest release for Grayscale publishing.
- Update grayscale rules, and set empty grayscale rules.
- Deletes the grayscale cluster and associated namespace. Why is it associated with cluster, rather than with namespace, because the original Apollo did not have a grayscale design, followed by grayscale, in order to avoid namespace drastic changes, in cluster to join the father and son logic (consulted author).
- Record the release history. Audit is convenient based on whether the merge record is discarded grayscale or merged after deletion.
There are many types of publish operations, and the constants of Apollo are as follows:
public interface ReleaseOperation { int NORMAL_RELEASE = 0;//普通发布 int ROLLBACK = 1;// 回滚 int GRAY_RELEASE = 2;// 灰度发布 int APPLY_GRAY_RULES = 3;// 灰度规则更新 int GRAY_RELEASE_MERGE_TO_MASTER = 4;// 灰度合并回主分支发布 int MASTER_NORMAL_RELEASE_MERGE_TO_GRAY = 5;// 主分支发布灰度自动发布 int MATER_ROLLBACK_MERGE_TO_GRAY = 6;// 主分支回滚灰度自动发布 int ABANDON_GRAY_RELEASE = 7;//放弃灰度 int GRAY_RELEASE_DELETED_AFTER_MERGE = 8;// 灰度版本合并后删除}
Summarize the admin release process:
4. Summary
Combine the portal and admin to see: