openstack4j 原始碼分析(一) 入口
g# openstack4j 原始碼分析之入口
背景
去年有個整合多個openstack平臺的專案,底層是華為、華3等不同平臺的openstack環境,應用管理層為java。雖然各平臺功能與原生openstack有所增加,但總體介面風格還是openstack的邏輯。由於openstack介面眾多,一個個去適配介面的工作量巨大,所以決定基於openstack的java sdk來開發。對比了幾種常見sdk,最後決定選用openstack4j來開發。
- Apache jclouds apache的開源sdk,大而全、雜,可以對接所有常見的雲平臺,文件較少,使用maven引入。
- openstack-java-sdk
- openstack4j 官網資料、文件豐富,介面上手簡單,更新快。
結構
openstack4j下面包含2個包,分別為:
connectors
實現了不同型別的http請求core
openstack4j核心包
而core下面又分了5個資料夾:api
openstack4j所有功能的介面common
公共父類model
sdk中用到的所有modelcore.transport
對於http請求的處理openstack
呼叫openstack的具體功能實現
入口
openstack4j的官網demo給出的入口是
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)。
OSClientV2 與 OSClientV3均為OSClient介面類的內部類,通過下面的程式碼可以看到,除了在認證模組有所區別外,其他模組沒有任何區別。
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等方法來接收外界傳入的登入所需資訊。
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物件,然後進行認證,完成了入口處的程式碼邏輯。
可以看到,為了避免由於openstack的認證方式更改而帶來的openstack4j認證物件的劇烈改動,入口類之間的耦合很低,易於擴充套件。使用建造者模式(Builder Pattern)生成認證資訊,將複雜的構建與其表示相分離,使得同樣的構建可以建立不同的表示。對於不同的認證方式,只需要增加或者減少部分組合方法即可。
而對於大版本之間的不同,如V2和V3,則使用工廠模式(Factory Pattern),IOSClientBuilder定義一個建立物件的介面,讓其子類自己決定例項化哪一個工廠類,工廠模式使其建立過程延遲到子類進行。當出現認證版本之間的差異時,只需要在IOSClientBuilder介面類中建立自己的靜態工廠介面類,就可以輕鬆完成認證過程的更改。我們對接華為、華3等平臺時,對於不同的認證方式,就是使用這種方式,大大減少了開發量。