去年有個整合多個openstack平臺的項目,底層是華爲、華3等不一樣平臺的openstack環境,應用管理層爲java。雖然各平臺功能與原生openstack有所增長,但整體接口風格仍是openstack的邏輯。因爲openstack接口衆多,一個個去適配接口的工做量巨大,因此決定基於openstack的java sdk來開發。對比了幾種常見sdk,最後決定選用openstack4j來開發。java
Apache jclouds apache的開源sdk,大而全、雜,能夠對接全部常見的雲平臺,文檔較少,使用maven引入。git
openstack-java-sdk 由愛好者開發及維護的sdk,更新很慢,github的demo已經不能成功鏈接最新的openstack版本。github
openstack4j 官網資料、文檔豐富,接口上手簡單,更新快。apache
openstack4j的官網demo給出的入口是api
OSClient.OSClientV3 os = OSFactory.builderV3() .endpoint("http://127.0.0.1:5000/v3") .credentials("admin", "secret", Identifier.byName("Default")) .scopeToProject(Identifier.byName("admin")) .authenticate();
OSFactory是一個抽象類,經過它咱們能夠建立出不一樣的OSClient,而OSClient則是咱們用來操做openstack的接口類。OSClient分爲V2和V3版本,對應openstack V2 與 V3版本的認證模塊(Keystone)。dom
OSClientV2 與 OSClientV3均爲OSClient接口類的內部類,經過下面的代碼能夠看到,除了在認證模塊有所區別外,其餘模塊沒有任何區別。maven
interface OSClientV2 extends OSClient<OSClient.OSClientV2> { Access getAccess(); org.openstack4j.api.identity.v2.IdentityService identity(); }
interface OSClientV3 extends OSClient<OSClient.OSClientV3> { Token getToken(); org.openstack4j.api.identity.v3.IdentityService identity(); }
OSFactory工廠類是使用建造者模式(Builder Pattern)來將複雜的對象構造過程和主類分離的,具體的對象構造行爲是由OSClientBuilder來完成,其中包含了endpoint、credentials、scopeToProject等方法來接收外界傳入的登陸所需信息。ide
public abstract class OSClientBuilder<R, T extends IOSClientBuilder<R, T>> implements IOSClientBuilder<R, T> { String endpoint; String user; String password; public T endpoint(String endpoint) { this.endpoint = endpoint; return (T) this; } public T credentials(String user, String password) { this.user = user; this.password = password; return (T) this; }
登陸信息保存在OSClientBuilder對象中,而後經過authenticate()方法,根據不一樣的版本進行認證。源碼分析
public static class ClientV2 extends OSClientBuilder<OSClientV2, IOSClientBuilder.V2> implements IOSClientBuilder.V2 { @Override public OSClientV2 authenticate() throws AuthenticationException { if (tokenId != null) { checkArgument(tenantName != null || tenantId != null, "TenantId or TenantName is required when using Token Auth"); return (OSClientV2) OSAuthenticator.invoke(new TokenAuth(tokenId, tenantName, tenantId), endpoint, perspective, config, provider); } if (raxApiKey) { return (OSClientV2) OSAuthenticator.invoke( new RaxApiKeyCredentials(user, password), endpoint, perspective, config, provider); } return (OSClientV2) OSAuthenticator.invoke( new Credentials(user, password, tenantName, tenantId), endpoint, perspective, config, provider); } }
public static class ClientV3 extends OSClientBuilder<OSClientV3, IOSClientBuilder.V3> implements IOSClientBuilder.V3 { @Override public OSClientV3 authenticate() throws AuthenticationException { if (tokenId != null && tokenId.length() > 0) return (OSClientV3) OSAuthenticator.invoke(new KeystoneAuth(tokenId, scope), endpoint, perspective, config, provider); return (OSClientV3) OSAuthenticator.invoke(new KeystoneAuth(user, password, domain, scope), endpoint, perspective, config, provider); } }
入口處的代碼主要關聯三個類(接口),OSFactory、OSClientBuilder(IOSClientBuilder)、OSClient,由OSFactory調用OSClientBuilder類構建OSClient對象,而後進行認證,完成了入口處的代碼邏輯。ui
能夠看到,爲了不因爲openstack的認證方式更改而帶來的openstack4j認證對象的劇烈改動,入口類之間的耦合很低,易於擴展。使用建造者模式(Builder Pattern)生成認證信息,將複雜的構建與其表示相分離,使得一樣的構建能夠建立不一樣的表示。對於不一樣的認證方式,只須要增長或者減小部分組合方法便可。
而對於大版本之間的不一樣,如V2和V3,則使用工廠模式(Factory Pattern),IOSClientBuilder定義一個建立對象的接口,讓其子類本身決定實例化哪個工廠類,工廠模式使其建立過程延遲到子類進行。當出現認證版本之間的差別時,只須要在IOSClientBuilder接口類中建立本身的靜態工廠接口類,就能夠輕鬆完成認證過程的更改。咱們對接華爲、華3等平臺時,對於不一樣的認證方式,就是使用這種方式,大大減小了開發量。