美文网首页Ovirt虚拟化技术
【Ovirt 笔记】RestAPI 调用机制分析和整理

【Ovirt 笔记】RestAPI 调用机制分析和整理

作者: 58bc06151329 | 来源:发表于2018-12-29 07:34 被阅读0次

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

分析整理的版本为 Ovirt 4.2.3 版本。

1. 概述

RestAPI

  • 一种软件架构设计风格,提供了一组设计原则和约束条件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。在 REST 中所有的东西都是资源,全部通过 URI 进行唯一标识。
  • RestAPI 对资源的操作主要有以下几种方法。
方法 作用
GET 查看资源
POST 创建资源
PUT 更新资源
DELETE 移除资源

2. 项目中 RestAPI 的使用

  • 查看 RestAPI 会使用 https://<ip>/api 地址访问项目 API。
<api>
<link href="/api/capabilities" rel="capabilities"/>
<link href="/api/clusters" rel="clusters"/>
<link href="/api/clusters?search={query}" rel="clusters/search"/>
<link href="/api/datacenters" rel="datacenters"/>
<link href="/api/datacenters?search={query}" rel="datacenters/search"/>
<link href="/api/events" rel="events"/>
<link href="/api/events;from={event_id}?search={query}" rel="events/search"/>
<link href="/api/hosts" rel="hosts"/>
<link href="/api/hosts?search={query}" rel="hosts/search"/>
<link href="/api/networks" rel="networks"/>
<link href="/api/networks?search={query}" rel="networks/search"/>
<link href="/api/roles" rel="roles"/>
<link href="/api/storagedomains" rel="storagedomains"/>
<link href="/api/storagedomains?search={query}" rel="storagedomains/search"/>
<link href="/api/tags" rel="tags"/>
<link href="/api/templates" rel="templates"/>
<link href="/api/templates?search={query}" rel="templates/search"/>
<link href="/api/users" rel="users"/>
<link href="/api/users?search={query}" rel="users/search"/>
<link href="/api/groups" rel="groups"/>
<link href="/api/groups?search={query}" rel="groups/search"/>
<link href="/api/domains" rel="domains"/>
<link href="/api/vmpools" rel="vmpools"/>
<link href="/api/vmpools?search={query}" rel="vmpools/search"/>
<link href="/api/vms" rel="vms"/>
<link href="/api/vms?search={query}" rel="vms/search"/>
<link href="/api/vms/brief" rel="vms/brief"/>
<link href="/api/vms/logoff" rel="vms/logoff"/>
<link href="/api/disks" rel="disks"/>
<link href="/api/disks?search={query}" rel="disks/search"/>
<link href="/api/jobs" rel="jobs"/>
<link href="/api/storageconnections" rel="storageconnections"/>
<link href="/api/vnicprofiles" rel="vnicprofiles"/>
<link href="/api/permissions" rel="permissions"/>
......

查看资源(GET)

例如:

https://<ip>/api/datacenters/<id>

创建资源(POST)

例如:

POST https://<ip>/api/datacenters/

更新资源(PUT)

例如:

PUT https://<ip>/ovirt-engine/api/datacenters/<id>

移除资源(DELETE)

例如:

DELETE https://<ip>/api/datacenters/<id>

3. 项目中实现

  • ovirt 项目 RestAPI 工程包含了 6 个模块。
模块名称 说明
restapi-defination RestAPI 定义模块
restapi-parent Rest API 后端集成模块(包含 jaxrs、types、webapp、interface、apidoc 等模块)
restapi-jaxrs RestAPI 后端的资源集成模块
restapi-types RestAPI 后端类型(实体)映射模块
restapi-webapp RestAPI 网站(包含 RestAPI 服务器访问路径定义,一些过滤器的设置)
restapi-apidoc RestAPI 文档模块

3.1 restapi-defination 定义

  • restapi-defination 模块包含了 5 个目录。如下表 (表 1)。
目录 说明
org.ovirt.engine.api.model 数据模型(RestAPI 实体类),初始包含了几个注解、工具类。
org.ovirt.engine.api.resource 资源模块(RestAPI 资源接口),初始包含了几个通用接口。
org.ovirt.engine.api.rsdl RestAPI rsdl 列表模块,包含一些工具类,封装的 rsdl 相关实体类。
org.ovirt.engine.api.utils RestAPI 工具类。
v3 定义了 RestAPI v3 版本的 rsdl.xml 还有 XML schema(api.xsd、api.xjb) 文件。
  • 该模块 org.ovirt.engine.api.model 和 org.ovirt.engine.api.resource 目录随着编译自动生成实体类型类和资源接口。
  • restapi-defination 模块 pom.xml 文件中定义了插件的执行。
  • 从 maven 库中拉取 model.jar 自动放置 /restapi/interface/definition/target/generated-resources/ 目录下。
<!-- Add the model .jar file as a generated resource: -->
<execution>
      <id>copy-model-file</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>copy</goal>
            </goals>
            <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>org.ovirt.engine.api</groupId>
                  <artifactId>model</artifactId>
                  <version>${model.version}</version>
                  <type>jar</type>
                  <classifier>sources</classifier>
                  <outputDirectory>${project.basedir}/target/generated-resources</outputDirectory>
                  <destFileName>model.jar</destFileName>
                </artifactItem>
              </artifactItems>
            </configuration>
</execution>

model.jar

  • 项目包含 ovirt 引擎 RestAPI 的规范,也称为模型。
  • 可以从 https://github.com/oVirt/ovirt-engine-api-model 下载源码。
  • Type 由 Java 接口表示。例如,Vm.java 文件包含 Vm 实体的规范,如下所示。
    • 这些接口的方法表示数据类型的属性,包括它们的类型和名称。
@Type
public interface Vm extends VmBase {
    String stopReason();
    Date startTime();
    Date stopTime();
    ...
}
  • Service API 也由 Java 接口表示。例如,VmService.java 文件包含 Vm Service 的规范,如下所示。
    • 操作(如 In、Out 等)表示为嵌套接口。这些嵌套接口的名称与操作的名称相对应,方法与操作的参数相对应。
@Service
public interface VmService extends MeasurableService {
    interface Start {
        @In Boolean pause();
        @In Vm vm();
        @In Boolean useCloudInit();
        @In Boolean useSysprep();
        @In Boolean async();
    }
    ...
}
  • Java 语言支持使用 JavaDoc 注释在代码本身中添加文档。这些注释以 /** 开始,以 */ 结束,并且可以在定义任何元素之前添加,比如接口和方法。这些 JavaDoc 注释是用于记录规范的机制。例如,可以记录 Vm 类型,如下所示。
/**
 * Represents a virtual machine.
 */
@Type
public interface Vm extends VmBase {
    ...
}
  • 可以用类似的方式记录属性,只需将 JavaDoc 注释放在表示该属性的方法的定义之前。
/**
 * Represents a virtual machine.
 */
@Type
public interface Vm extends VmBase {
    /**
     * Contains the reason why this virtual machine was stopped. This reason is
     * provided by the user, via the GUI or via the API.
     */
    String stopReason();
    ...
}
  • Service 的操作同样如此。
/**
 * This service manages a specific virtual machine.
 */
@Service
public interface VmService extends MeasurableService {

    /**
     * This operation will start the virtual machine managed by this
     * service, if it isn't already running.
     */
    interface Start {
        /**
         * Specifies if the virtual machine should be started in pause
         * mode. It is an optional parameter, if not given then the
         * virtual machine will be started normally.
         */
        @In Boolean pause();
        ...
    }
    ...
}
  • 这些 JavaDoc 注释由作为系统一部分的工具处理,并且用于自动生成参考文档。
    • 一个工具生成文档的 示例
    • JavaDoc 注释有自己的格式,但是 ovirt 文档工具没有使用它。这些工具支持了 AsciiDoc。这意味着 JavaDoc 注释可以包含丰富的文本和示例。
/**
 * Specifies if the virtual machine should be started in pause
 * mode. It is an _optional_ parameter, if not given then the
 * virtual machine will be started normally.
 *
 * To use this parameter with the Python SDK you can use the
 * following code snippet:
 *
 * [source,python]
 * ----
 * # Find the virtual machine:
 * vm = api.vms.get(name="myvm")
 *
 * # Start the virtual machine paused:
 * vm.start(
 *   params.Action(
 *     pause=True
 *   )
 * )
 * ----
 */
@In Boolean pause();

metamodel

  • 这个项目包含 ovirt 引擎 API 元模型。它是一组从 API 模型(model)读取、分析和生成代码的工具。
    • 通过该工具将 model.jar 中代码转换为 JAX-RS RestAPI 应用接口。
  • 可以从 https://github.com/oVirt/ovirt-engine-api-metamodel 下载源码。

  • 后续提示目录除特殊说明,都是 restapi-defination 模块中目录。
  • 提取 model.jar 中包含的 API 文档。
<!-- Extract the API documentation contained in the model
               documentation artifact, so that it can then be added
               to the generated .war file: -->
<execution>
            <id>extract-model-documentation</id>
            <phase>generate-resources</phase>
            <goals>
              <goal>unpack</goal>
            </goals>
            <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>org.ovirt.engine.api</groupId>
                  <artifactId>model</artifactId>
                  <version>${model.version}</version>
                  <type>jar</type>
                  <classifier>javadoc</classifier>
                  <outputDirectory>${project.basedir}/target/generated-resources</outputDirectory>
                </artifactItem>
              </artifactItems>
            </configuration>
</execution>
  • 文档放在 /restapi/interface/definition/target/generated-resources/ 目录下。
    • 文档访问页面为 model.html

  • 编译过程中通过 RsdlManager 类生成 rsdl 文件。
    • 自动生成到 /restapi/interface/definition/target/classes/v4/ 目录下。
<!-- Generate the RSDL: -->
<execution>
            <id>generate-rsdl</id>
            <phase>compile</phase>
            <goals>
              <goal>java</goal>
            </goals>
            <configuration>
              <mainClass>org.ovirt.engine.api.rsdl.RsdlManager</mainClass>
              <arguments>
                <argument>${application.baseuri}</argument>
                <argument>${project.build.outputDirectory}/v4/rsdl.xml</argument>
                <argument>${project.build.outputDirectory}/v4/rsdl_gluster.xml</argument>
              </arguments>
            </configuration>
</execution>
  • RsdlManager 中加载解析 rsdl_metadata.yaml 元数据资源文件,生成 rsdl。
private static final String METADATA_FILE_NAME = "/rsdl_metadata.yaml";

private static Rsdl buildRsdl(MetaData metadata, List<String> rels) throws IOException,
            ClassNotFoundException {
        RsdlBuilder builder = new RsdlBuilder(rels, metadata)
        .description(RSDL_DESCRIPTION)
        .rel(RSDL_REL)
                .href(QUERY_PARAMETER + RSDL_CONSTRAINT_PARAMETER)
        .schema(new SchemaBuilder()
            .rel(SCHEMA_REL)
            .href(QUERY_PARAMETER + SCHEMA_CONSTRAINT_PARAMETER)
            .name(SCHEMA_NAME)
            .description(SCHEMA_DESCRIPTION)
            .build())
        .generalMetadata(new GeneralMetadataBuilder()
            .rel(GENERAL_METADATA_REL)
            .href("*")
            .name(GENERAL_METADATA_NAME)
            .description(GENERAL_METADATA_DESCRIPTION)
            .build());
        Rsdl rsdl = builder.build();
        return rsdl;
}

private static MetaData loadMetaData() throws IOException {
        try (InputStream in = RsdlManager.class.getResourceAsStream(METADATA_FILE_NAME)) {
            if (in == null) {
                throw new IOException("Can't find metadata from resource \"" + METADATA_FILE_NAME + "\"");
            }
            return loadMetaData(in);
        }
}

  • 解析 model 并生成 XML 和 JSON 描述,XML schema 与 Java 代码。
<!-- Parse the model and generate the XML and JSON descriptions, the
               XML schema and the Java code: -->
<execution>
            <id>generate-code</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>java</executable>
              <classpathScope>runtime</classpathScope>
              <arguments>
                <argument>-classpath</argument>
                <classpath/>
                <argument>org.ovirt.api.metamodel.tool.Main</argument>
                <argument>org.ovirt.api.metamodel.tool.Tool</argument>
                <argument>--model=${project.basedir}/target/generated-resources/model.jar</argument>
                <argument>--in-schema=${project.basedir}/src/main/schema/api.xsd</argument>
                <argument>--out-schema=${project.basedir}/target/generated-resources/v4/api.xsd</argument>
                <argument>--jaxrs=${project.basedir}/target/generated-sources/model</argument>
                <argument>--jaxrs-package=^services\.(.*)$=org.ovirt.engine.api.resource.$1</argument>
                <argument>--jaxrs-package=org.ovirt.engine.api.resource</argument>
              </arguments>
            </configuration>
</execution>
  • 执行 org.ovirt.api.metamodel.tool.Main 实现就是通过反射执行 org.ovirt.api.metamodel.tool.Tool 类的 run() 方法。
  • 后续的 <argument> 都作为 Tool 的参数传入,下表(表 2)中说明。
  • metamodel 工具中提供了 ModelAnalyzer 工具,用于解析 model。
序号 参数 说明
1 --model 为模型解析器提供解析源。
2 --in-schema 指定需要解析的 XML schema 源,/src/main/schema/api.xsd 文件。
3 --out-schema 输出解析后重新生成的 XML schema,自动生成为 /restapi/interface/definition/target/generated-resources/v4/api.xsd 文件。
4 --jaxrs 设置 JAX-RS 源码目录为 /restapi/interface/definition/target/generated-sources/model,加上 5、6 设置自动生成 JAX-RS 源码。
5 --jaxrs-package 设置 JAX-RS 包路径为 /restapi/interface/definition/target/generated-sources/model/org/ovirt/engine/api/resource/$1,其中 $1 通过正则 ^services.(.*)$ 获取 model.jar 中包名称,然后一一对应生成。
6 --jaxrs-package 设置 JAX-RS 包路径为 /restapi/interface/definition/target/generated-sources/model/org/ovirt/engine/api/resource/

--model

private static final String MODEL_OPTION = "model";
File modelFile = (File) line.getParsedOptionValue(MODEL_OPTION);
// Analyze the model files:
Model model = new Model();
ModelAnalyzer modelAnalyzer = new ModelAnalyzer();
modelAnalyzer.setModel(model);
modelAnalyzer.analyzeSource(modelFile);

--in-schema--out-schema

private static final String IN_SCHEMA_OPTION = "in-schema";
private static final String OUT_SCHEMA_OPTION = "out-schema";
File inSchemaFile = (File) line.getParsedOptionValue(IN_SCHEMA_OPTION);
File outSchemaFile = (File) line.getParsedOptionValue(OUT_SCHEMA_OPTION);
// Generate the XML schema:
if (inSchemaFile != null && outSchemaFile != null) {
            schemaGenerator.setInFile(inSchemaFile);
            schemaGenerator.setOutFile(outSchemaFile);
            schemaGenerator.generate(model);
}

--jaxrs--jaxrs-package

private static final String JAXRS_OPTION = "jaxrs";
File jaxrsDir = (File) line.getParsedOptionValue(JAXRS_OPTION);
// Generate the JAX-RS source:
if (jaxrsDir != null) {
            FileUtils.forceMkdir(jaxrsDir);
            jaxrsGenerator.setOutDir(jaxrsDir);
            jaxrsGenerator.generate(model);
            // Generate the JAX-RS helper classes):
            jaxrsHelperGenerator.setOutDir(jaxrsDir);
            jaxrsHelperGenerator.generate(model);
}

  • 解析 model 并将其中枚举生成为 JAXB 枚举。
<!-- Parse the model and generate replacements for the JAXB enums: -->
<execution>
            <id>generate-enums-jaxb</id>
            <phase>process-sources</phase> <!-- TODO: REVISIT phase -->
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>java</executable>
              <classpathScope>runtime</classpathScope>
              <arguments>
                <argument>-classpath</argument>
                <classpath/>
                <argument>org.ovirt.api.metamodel.tool.Main</argument>
                <argument>org.ovirt.api.metamodel.tool.EnumGenerationToolJaxb</argument>
                <argument>--model=${project.basedir}/target/generated-resources/model.jar</argument>
                <argument>--xjc=${project.basedir}/target/generated-sources/xjc-v4</argument>
              </arguments>
            </configuration>
</execution>
  • 执行 org.ovirt.api.metamodel.tool.Main 实现就是通过反射执行 org.ovirt.api.metamodel.tool.EnumGenerationToolJaxb 类的 run() 方法。
  • 后续的 <argument> 都作为 Tool 的参数传入,下表(表 3)中说明。
  • metamodel 工具中提供了 ModelAnalyzer 工具,用于解析 model。
序号 参数 说明
1 --model 为模型解析器提供解析源。
2 --xjc 最后生成至目录 /restapi/interface/definition/target/generated-sources/xjc-v4/

--xjc

// Generate the enums:
if (xjcDir != null) {
            FileUtils.forceMkdir(xjcDir);
            enumGenerator.setOutDir(xjcDir);
            enumGenerator.generate(model);
}

  • 根据 API v4 版本的 XML schema 生成 Java 代码。
    • 最终生成至目录 /restapi/interface/definition/target/generated-sources/xjc-v4/
    • 目录下生成的包路径为 org.ovirt.engine.api.model
    • 依赖的 XML schema 文件所在目录 /restapi/interface/definition/target/generated-resources/v4/
      • XML schema 文件名称为 api.xsd。
    • 绑定JAXB 的配置文件(api.xjb )目录为 /src/main/schema/
      • 文件名为 api.xjb。
<!-- Generate the Java code from the XML schema of version 4 of the API: -->
<execution>
            <id>xjc-v4</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <generateDirectory>${project.basedir}/target/generated-sources/xjc-v4</generateDirectory>
              <generatePackage>org.ovirt.engine.api.model</generatePackage>
              <extension>true</extension>
              <schemaDirectory>${project.basedir}/target/generated-resources/v4</schemaDirectory>
              <schemaIncludes>
                <include>api.xsd</include>
              </schemaIncludes>
              <bindingDirectory>${project.basedir}/src/main/schema</bindingDirectory>
              <bindingIncludes>
                <include>api.xjb</include>
              </bindingIncludes>
            </configuration>
</execution>

  • 根据 API v3 版本的 XML schema 生成 Java 代码。
    • 最终生成至目录 /restapi/interface/definition/target/generated-sources/xjc-v3/
    • 目录下生成的包路径为 org.ovirt.engine.api.v3.types
    • 依赖的 XML schema 文件所在目录 /src/main/resources/v3/
      • XML schema 文件名称为 api.xsd。
    • 绑定JAXB 的配置文件(api.xjb )目录为 /src/main/resources/v3/
      • 文件名为 api.xjb。
<!-- Generate the Java code from the XML schema of version 3 of the API: -->
<execution>
            <id>xjc-v3</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <generateDirectory>${project.basedir}/target/generated-sources/xjc-v3</generateDirectory>
              <generatePackage>org.ovirt.engine.api.v3.types</generatePackage>
              <extension>true</extension>
              <schemaDirectory>${project.basedir}/src/main/resources/v3</schemaDirectory>
              <schemaIncludes>
                <include>api.xsd</include>
              </schemaIncludes>
              <bindingDirectory>${project.basedir}/src/main/resources/v3</bindingDirectory>
              <bindingIncludes>
                <include>api.xjb</include>
              </bindingIncludes>
            </configuration>
</execution>

  • 将生成的源码加入源码路径,便于后续编译成 class 文件。
<!-- This is needed to avoid having to manually add the generated sources
           directory to the source paths in Eclipse: -->
<executions>
          <execution>
            <id>add-source</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>add-source</goal>
            </goals>
            <configuration>
              <sources>
                <source>${project.build.directory}/generated-sources/xjc-v3</source>
                <source>${project.build.directory}/generated-sources/xjc-v4</source>
                <source>${project.build.directory}/generated-sources/model</source>
              </sources>
            </configuration>
</execution>
  • 将需要用到的资源也加入资源路径,便于后续编译。
<!-- Include the regular resources directory and also the generated
           resources, including the descriptions of the model and the XML
           schema: -->
<resource>
        <directory>${project.basedir}/src/main/resources</directory>
</resource>
<resource>
        <directory>${project.basedir}/target/generated-resources</directory>
</resource>
  • 最终生成的 restapi-definition.jar 目录对应关系。
目录 来源
org.ovirt.engine.api.model 增加 /restapi/interface/definition/target/generated-sources/xjc-v4/org/ovirt/engine/api/model/ 目录中内容。
org.ovirt.engine.api.resourcel 增加 /restapi/interface/definition/target/generated-sources/model/org/ovirt/engine/api/resource/ 目录中内容。
org.ovirt.engine.api.rsdl 不变
org.ovirt.engine.api.utilsl 不变
org.ovirt.engine.api.v3 /restapi/interface/definition/target/generated-sources/xjc-v3/org/ovirt/engine/api/v3/types/ 目录中内容。
v3 不变
v4 中的 api.xsd 文件 /restapi/interface/definition/target/generated-resources/v4/api.xsd。
v4 资源文件中 rsdl.xml 和 rsdl_gluster.xml 文件 RsdlManager 类直接生成。
API 相关文档 /restapi/interface/definition/target/generated-resources/ 目录下。

3.2 restapi-jaxrs 资源集成

  • 主要完成了对 restapi-definition 资源接口定义的实现。
  • 例如 restapi-definition 中生成的数据中心资源接口(DataCenterResource ),JSA-RS 应用的。
......
@Produces({ ApiMediaType.APPLICATION_XML, ApiMediaType.APPLICATION_JSON })
public interface DataCenterResource  {
    @GET
    default public DataCenter doGet() {
        DataCenter dataCenter = get();
        follow(dataCenter);
        return dataCenter;
    }

    default public DataCenter get() {
        throw new UnsupportedOperationException();
    }
    
    @PUT
    @Consumes({ ApiMediaType.APPLICATION_XML, ApiMediaType.APPLICATION_JSON })
    default public DataCenter update(DataCenter dataCenter) {
        throw new UnsupportedOperationException();
    }
    
    @DELETE
    default public Response remove() {
        throw new UnsupportedOperationException();
    }
    
    default public void follow (ActionableResource entity) {
    }
    
    @Path("storagedomains")
    AttachedStorageDomainsResource getStorageDomainsResource();
    
    @Path("clusters")
    ClustersResource getClustersResource();
    
    @Path("networks")
    DataCenterNetworksResource getNetworksResource();
    
    @Path("permissions")
    AssignedPermissionsResource getPermissionsResource();
    
    @Path("quotas")
    QuotasResource getQuotasResource();
    
    @Path("qoss")
    QossResource getQossResource();
    
    @Path("iscsibonds")
    IscsiBondsResource getIscsiBondsResource();
    
}
  • restapi-jaxrs 的对资源接口的实现。
......
public class BackendDataCenterResource extends AbstractBackendSubResource<DataCenter, StoragePool>
        implements DataCenterResource {

    public static final String FORCE = "force";

    private final BackendDataCentersResource parent;

    public BackendDataCenterResource(String id, BackendDataCentersResource parent) {
        super(id, DataCenter.class, StoragePool.class);
        this.parent = parent;
    }

    @Override
    public DataCenter get() {
        return performGet(QueryType.GetStoragePoolById, new IdQueryParameters(guid));
    }

    @Override
    public DataCenter update(DataCenter incoming) {
        return performUpdate(incoming,
                new QueryIdResolver<>(QueryType.GetStoragePoolById, IdQueryParameters.class),
                ActionType.UpdateStoragePool,
                new UpdateParametersProvider());
    }

    @Override
    public AssignedPermissionsResource getPermissionsResource() {
        return inject(new BackendAssignedPermissionsResource(guid,
                                                             QueryType.GetPermissionsForObject,
                                                             new GetPermissionsForObjectParameters(guid),
                                                             DataCenter.class,
                                                             VdcObjectType.StoragePool));
    }

    @Override
    public AttachedStorageDomainsResource getStorageDomainsResource() {
        return inject(new BackendAttachedStorageDomainsResource(id));
    }

    @Override
    public DataCenterNetworksResource getNetworksResource() {
        return inject(new BackendDataCenterNetworksResource(id));
    }

    @Override
    public ClustersResource getClustersResource() {
        return inject(new BackendDataCenterClustersResource(id));
    }

    @Override
    public QuotasResource getQuotasResource() {
         return inject(new BackendQuotasResource(id));
    }

    @Override
    public IscsiBondsResource getIscsiBondsResource() {
        return inject(new BackendIscsiBondsResource(id));
    }

    public BackendDataCentersResource getParent() {
        return parent;
    }

    @Override
    protected DataCenter doPopulate(DataCenter model, StoragePool entity) {
        return parent.doPopulate(model, entity);
    }

    @Override
    protected DataCenter deprecatedPopulate(DataCenter model, StoragePool entity) {
        return parent.deprecatedPopulate(model, entity);
    }

    protected class UpdateParametersProvider implements
            ParametersProvider<DataCenter, StoragePool> {
        @Override
        public ActionParametersBase getParameters(DataCenter incoming, StoragePool entity) {
            return new StoragePoolManagementParameter(map(incoming, entity));
        }
    }

    /**
     * Get the storage pool (i.e. datacenter entity) associated with the given
     * cluster.
     */
    @SuppressWarnings("unchecked")
    public static StoragePool getStoragePool(DataCenter dataCenter, AbstractBackendResource parent) {
        StoragePool pool = null;
        if (dataCenter.isSetId()) {
            String id = dataCenter.getId();
            Guid guid;
            try {
                guid = new Guid(id); // can't use asGuid() because the method is static.
            } catch (IllegalArgumentException e) {
                throw new MalformedIdException(e);
            }
            pool = parent.getEntity(StoragePool.class, QueryType.GetStoragePoolById,
                    new IdQueryParameters(guid), "Datacenter: id=" + id);
        } else {
            String clusterName = dataCenter.getName();
            pool = parent.getEntity(StoragePool.class, QueryType.GetStoragePoolByDatacenterName,
                    new NameQueryParameters(clusterName), "Datacenter: name="
                            + clusterName);
            dataCenter.setId(pool.getId().toString());
        }
        return pool;
    }

    /**
     * Get the storage pools (i.e. datacenter entity) associated with the given
     * storagedomain.
     */
    @SuppressWarnings("unchecked")
    public static  List<StoragePool> getStoragePools(Guid storageDomainId, AbstractBackendResource parent) {
        return parent.getEntity(List.class,
                QueryType.GetStoragePoolsByStorageDomainId,
                new IdQueryParameters(storageDomainId),
                "Datacenters",
                true);
    }

    @Override
    public QossResource getQossResource() {
        return inject(new BackendQossResource(id));
    }

    @Override
    public Response remove() {
        get();
        StoragePoolParametersBase params = new StoragePoolParametersBase(asGuid(id));
        boolean force = ParametersHelper.getBooleanParameter(httpHeaders, uriInfo, FORCE, true, false);
        if (force) {
            params.setForceDelete(force);
        }
        return performAction(ActionType.RemoveStoragePool, params);
    }
}

3.3 restapi-types 后端类型(实体)映射

  • 该模块实现了 RestAPI 实体与服务端实体的互相转换。
  • 同样是数据中心资源为例。
    • 服务器后端实体 StoragePool 与 RestAPI 实体 DataCenter 的互相转换。
......
public class DataCenterMapper {

    @Mapping(from = DataCenter.class, to = StoragePool.class)
    public static StoragePool map(DataCenter model, StoragePool template) {
        StoragePool entity = template != null ? template : new StoragePool();
        if (model.isSetId()) {
            entity.setId(GuidUtils.asGuid(model.getId()));
        }
        if (model.isSetName()) {
            entity.setName(model.getName());
        }
        if (model.isSetDescription()) {
            entity.setdescription(model.getDescription());
        }
        if (model.isSetComment()) {
            entity.setComment(model.getComment());
        }
        if (model.isSetLocal()) {
            entity.setIsLocal(model.isLocal());
        }
        if (model.isSetStorageFormat()) {
            entity.setStoragePoolFormatType(StorageFormatMapper.map(model.getStorageFormat(), null));
        }
        if (model.isSetVersion() && model.getVersion().getMajor() != null && model.getVersion().getMinor() != null) {
            entity.setCompatibilityVersion(VersionMapper.map(model.getVersion()));
        }

        if (model.isSetMacPool() && model.getMacPool().isSetId()) {
            entity.setMacPoolId(GuidUtils.asGuid(model.getMacPool().getId()));
        }

        if (model.isSetQuotaMode()) {
            entity.setQuotaEnforcementType(map(model.getQuotaMode()));
        }

        return entity;
    }

    @Mapping(from = StoragePool.class, to = DataCenter.class)
    public static DataCenter map(StoragePool entity, DataCenter template) {
        DataCenter model = template != null ? template : new DataCenter();
        model.setId(entity.getId().toString());
        model.setName(entity.getName());
        model.setLocal(entity.isLocal());

        if (!StringUtils.isEmpty(entity.getdescription())) {
                model.setDescription(entity.getdescription());
        }
        if (!StringUtils.isEmpty(entity.getComment())) {
            model.setComment(entity.getComment());
        }
        if (entity.getStatus()!=null) {
            model.setStatus(mapDataCenterStatus(entity.getStatus()));
        }
        if (entity.getCompatibilityVersion() != null) {
            model.setVersion(VersionMapper.map(entity.getCompatibilityVersion()));
        }
        if (entity.getStoragePoolFormatType()!=null) {
            StorageFormat storageFormat = StorageFormatMapper.map(entity.getStoragePoolFormatType(), null);
            if (storageFormat!=null) {
                model.setStorageFormat(storageFormat);
            }
        }

        if (entity.getMacPoolId() != null) {
            model.setMacPool(new MacPool());
            model.getMacPool().setId(entity.getMacPoolId().toString());
        }

        if (entity.getQuotaEnforcementType() != null) {
            model.setQuotaMode(map(entity.getQuotaEnforcementType()));
        }

        return model;
    }

    private static DataCenterStatus mapDataCenterStatus(StoragePoolStatus status) {
        switch (status) {
        case Contend:
            return DataCenterStatus.CONTEND;
        case Maintenance:
            return DataCenterStatus.MAINTENANCE;
        case NotOperational:
            return DataCenterStatus.NOT_OPERATIONAL;
        case NonResponsive:
            return DataCenterStatus.PROBLEMATIC;
        case Uninitialized:
            return DataCenterStatus.UNINITIALIZED;
        case Up:
            return DataCenterStatus.UP;
        default:
            throw new IllegalArgumentException("Unknown data center status \"" + status + "\"");
        }
    }

    @Mapping(from = QuotaEnforcementTypeEnum.class, to = QuotaModeType.class)
    public static QuotaModeType map(QuotaEnforcementTypeEnum type) {
        switch (type) {
        case DISABLED:
            return QuotaModeType.DISABLED;
        case HARD_ENFORCEMENT:
            return QuotaModeType.ENABLED;
        case SOFT_ENFORCEMENT:
            return QuotaModeType.AUDIT;
        default:
            throw new IllegalArgumentException("Unknown quota enforcement type \"" + type + "\"");
        }
    }

    @Mapping(from = QuotaModeType.class, to = QuotaEnforcementTypeEnum.class)
    public static QuotaEnforcementTypeEnum map(QuotaModeType type) {
        switch (type) {
        case DISABLED:
            return QuotaEnforcementTypeEnum.DISABLED;
        case ENABLED:
            return QuotaEnforcementTypeEnum.HARD_ENFORCEMENT;
        case AUDIT:
            return QuotaEnforcementTypeEnum.SOFT_ENFORCEMENT;
        default:
            throw new IllegalArgumentException("Unknown quota mode type \"" + type + "\"");
        }
    }
}

3.4 restapi-apidoc 文档

  • restapi-apidoc 模块中 jboss-web.xml 文件中定义了访问路径 /ovirt-engine/apidoc
    • 如果要通过网页上查看 API 文档,只需要访问 https://<ip>/ovirt-engine/apidoc
<jboss-web
  xmlns="http://www.jboss.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_8_0.xsd"
  version="8.0">

  <context-root>/ovirt-engine/apidoc</context-root>
  <symbolic-linking-enabled>true</symbolic-linking-enabled>

</jboss-web>
  • restapi-apidoc 模块中 web.xml 文件中定义了主页名称为 model.html。

3.5 restapi-webapp RestAPI 网站

  • restapi-webapp 模块中 jboss-web.xml 文件中定义了访问路径 /ovirt-engine/api
  • restapi-webapp 模块中 web.xml 文件中定义了一些过滤器。
过滤器名称 作用
CORSSupportFilter 跨域支持过滤器,可以通过 ConfigValues.CORSSupport 参数设置是否支持。
CSRFProtectionFilter 伪造请求恶意攻击防护,可以通过 ConfigValues.CSRFProtection 参数设置是否支持。
RestApiSessionValidationFilter RestAPI session 验证。
SessionValidationFilter 系统 session 验证。
SsoRestApiAuthFilter 单点登录 RestAPI 用户授权。
SsoRestApiNegotiationFilter 单点登录 RestAPI 协商验证。
VersionFilter 访问 RestAPI 默认使用版本,ovirt-engine.conf 配置文件中定义。ENGINE_API_DEFAULT_VERSION = 4。使用 API v4 版本。
  • 还提供了一个对 API 描述访问的 servlet。支持多种 MIME 类型。
<servlet>
        <servlet-name>ModelServlet</servlet-name>
        <servlet-class>org.ovirt.api.metamodel.server.ModelServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ModelServlet</servlet-name>
        <url-pattern>/v4/model</url-pattern>
        <url-pattern>/v4/model.xml</url-pattern>
        <url-pattern>/v4/model.json</url-pattern>
        <url-pattern>/v4/model.jar</url-pattern>
        <url-pattern>/v4/model.zip</url-pattern>
        <url-pattern>/v4/model.html</url-pattern>
</servlet-mapping>

3.6 ovirt 4.2.3 新增接口的步骤

  • 以数据中心为例。
  1. 如果要增加实体类,需要在 model 的 types 中定义。
  • @Type 设置该对象为实体接口(资源)
  • @Link 设置关联的其他实体接口(资源)
  • @Deprecated 设置不建议使用。
@Type
public interface DataCenter extends Identified {
    Boolean local();
    StorageFormat storageFormat();

    Version version();
    Version[] supportedVersions();
    DataCenterStatus status();
    QuotaModeType quotaMode();

    @Link MacPool macPool();

    @Link StorageDomain[] storageDomains();

    @Link Cluster[] clusters();

    @Link Network[] networks();

    @Link Permission[] permissions();

    @Link Quota[] quotas();

    @Link Qos[] qoss();

    @Link IscsiBond[] iscsiBonds();
}
  • 枚举也需要设置为 @Type。
@Type
public enum DataCenterStatus {
    UNINITIALIZED,
    UP,
    MAINTENANCE,
    NOT_OPERATIONAL,
    PROBLEMATIC,
    CONTEND;
}
  1. 如果要增加资源接口,需要在 model 的 services 中定义。
  • @Service 设置该对象为资源服务接口。
  • @Out 设置该接口返回实体(资源)。
  • @In 设置该接口接收属性,例如。
    • filter 是否根据用户的权限进行筛选过滤。
    • async 设置是否异步执行更新。
    • 实体本身,设置接收的实体(资源)。
    • force 设置是否强制执行。
  • @InputDetail 定义接收的实体(资源)的属性集。
    • optional 选择性参数设置。
    • mandatory 强制性参数设置。
@Service
@Area("Virtualization")
public interface DataCenterService {

    interface Get extends Follow {
        @Out DataCenter dataCenter();

        @In Boolean filter();
    }

    interface Update {
        @InputDetail
        default void inputDetail() {
            optional(dataCenter().comment());
            optional(dataCenter().description());
            optional(dataCenter().local());
            optional(dataCenter().macPool().id());
            optional(dataCenter().name());
            optional(dataCenter().storageFormat());
            optional(dataCenter().version().major());
            optional(dataCenter().version().minor());
        }
       
        @In @Out DataCenter dataCenter();

        @In Boolean async();
    }

    interface Remove {
        
        @In Boolean force();

        @In Boolean async();
    }

    @Service AttachedStorageDomainsService storageDomains();
    @Service ClustersService clusters();
    @Service DataCenterNetworksService networks();
    @Service AssignedPermissionsService permissions();
    @Service QuotasService quotas();
    @Service QossService qoss();
    @Service IscsiBondsService iscsiBonds();
}
  1. rsdl-metadata.yaml 文件中定义添加的接口信息,如描述,参数等,最终会生成 rsdl.xml 文件。会在输入 https://<ip>/ovirt-engine/api?rsdl 访问显示。
- name: /datacenters/{datacenter:id}|rel=update
  description: update the specified data center in the system
  request:
    body:
      parameterType: DataCenter
      signatures:
      - mandatoryArguments: {}
        optionalArguments:
          datacenter.name: xs:string
          datacenter.description: xs:string
          datacenter.comment: xs:string
          datacenter.local: xs:boolean
          datacenter.version.major: xs:int
          datacenter.version.minor: xs:int
          datacenter.description: xs:string
          datacenter.storage_format: xs:string
          datacenter.mac_pool.id: xs:string
        description: update the specified data center in the system
- name: /datacenters|rel=get
  description: get a list of data centers in the system
  request:
    urlparams:
      search: {context: query, type: 'xs:string', value: 'search query', required: false}
      case_sensitive: {context: matrix, type: 'xs:boolean', value: true|false, required: false}
    headers:
      Filter: {value: true|false, required: false}
- name: /datacenters/{datacenter:id}|rel=get
  description: get the details of the specified data center in the system
  request:
    headers:
      Filter: {value: true|false, required: false}
- name: /datacenters/{datacenter:id}|rel=delete
  description: delete the specified data center in the system
  request:
    urlparams:
      force:
        context: matrix
        type: xs:boolean
        value: true|false
        required: false
- name: /datacenters|rel=add
  description: add a new data center to the system
  request:
    body:
      parameterType: DataCenter
      signatures:
      - mandatoryArguments:
          datacenter.local: xs:boolean
          datacenter.name: xs:string
        optionalArguments:
          datacenter.comment: xs:string
          datacenter.description: xs:string
          datacenter.storage_format: xs:string
          datacenter.version.major: xs:int
          datacenter.version.minor: xs:int
          datacenter.mac_pool.id: xs:string
        description: add a new data center to the system
  1. 如果需要将 RestAPI 实体与服务器后端实体关联,则需要在 restapi-types 模块中增加 Mapper 映射关系。

  2. 如果需要输入 https://<ip>/ovirt-engine/api 显示的 API 列表中显示接口,则需要在 ApiRootLinksCreator 类中进行定义,如果只需要在 https://<ip>/ovirt-engine/api?rsdl 中显示则不需要定义。

public static Collection<DetailedLink> getLinks(String baseUri) {
        Collection<DetailedLink> links = new LinkedList<>();
        links.add(createLink("clusters", LinkFlags.SEARCHABLE, baseUri));
        links.add(createLink("datacenters", LinkFlags.SEARCHABLE, baseUri));
        links.add(createLink("events", LinkFlags.SEARCHABLE, getEventParams(), baseUri));
        links.add(createLink("hosts", LinkFlags.SEARCHABLE, baseUri));
        links.add(createLink("networks", LinkFlags.SEARCHABLE, baseUri));
......
  • restapi-definition 模块的 org.ovirt.engine.api.model 目录中的类来自 /restapi/interface/definition/target/generated-sources/xjc-v4/org/ovirt/engine/api/model/ 目录,而该目录中大部分的源码又由 /restapi/interface/definition/target/generated-resources/v4/ 中的 api.xsd 生成。
    • org.ovirt.engine.api.model 中有个类 Action 是专门用于针对动作复杂的 Java 类的,是由 api.xsd 自动生成的。
    • 例如虚拟机开机操作,参数传递除了虚拟机对象 Vm 以外还需要很多其他的参数,这种情况下就可以通过 api.xsd 文件将这些参数设置给 Action 对象,最终生成的 Action 类中就包含了 Vm 等相关属性,可以通过 get 方法获取。
<xs:element name="action" type="Action"/>

  <xs:complexType name="Action">
    <xs:complexContent>
      <xs:extension base="BaseResource">
        <xs:sequence> 
......
          <xs:element maxOccurs="1" minOccurs="0" name="vm" type="Vm"/>
......          
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  • maxOccurs 对应的是该 element 实体出现的最多次数。
  • minOccurs 对应的是该 element 实体出现的最少次数。

4. 与 ovirt 3.4.5 区别

4.1 实现原理方式的区别

  • ovirt 3.4.5 中未使用提供 model.jar 模型自动生成源码的方式。
    • 直接在 restapi-definition 模块的 org.ovirt.engine.api.model 包中定义数据模型(RestAPI 实体类)
    • 直接在 org.ovirt.engine.api.resource 包中定义资源接口(RestAPI 资源接口类)。
    • 其他的模块关系保持了一致。
    • org.ovirt.engine.api.model 包中的 Action 类,还是需要通过 api.xsd 生成。
    • rsdl.xml 还是通过 rsdl-metadata.yaml 文件定义生成。

4.2 接口的区别

新增接口

接口 方法
affinitylabels add
affinitylabels get
affinitylabels/{affinitylabel:id} delete
affinitylabels/{affinitylabel:id} get
affinitylabels/{affinitylabel:id} update
affinitylabels/{affinitylabel:id}/hosts add
affinitylabels/{affinitylabel:id}/hosts get
affinitylabels/{affinitylabel:id}/hosts/{host:id} delete
affinitylabels/{affinitylabel:id}/hosts/{host:id} get
affinitylabels/{affinitylabel:id}/vms add
affinitylabels/{affinitylabel:id}/vms get
affinitylabels/{affinitylabel:id}/vms/{vm:id} delete
affinitylabels/{affinitylabel:id}/vms/{vm:id} get
clusterlevels get
clusterlevels/{clusterlevel:id} get
clusterlevels/{clusterlevel:id}/clusterfeatures get
clusterlevels/{clusterlevel:id}/clusterfeatures/{clusterfeature:id} get
clusters/{cluster:id}/enabledfeatures add
clusters/{cluster:id}/enabledfeatures get
clusters/{cluster:id}/enabledfeatures/{enabledfeature:id} delete
clusters/{cluster:id}/enabledfeatures/{enabledfeature:id} get
clusters/{cluster:id}/externalnetworkproviders get
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/getprofilestatistics getprofilestatistics
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks add
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks delete
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks get
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/activate activate
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/migrate migrate
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/stopmigrate stopmigrate
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id} delete
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id} get
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id}/replace replace
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id}/statistics get
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id}/statistics/{statistic:id} get
clusters/{cluster:id}/networkfilters get
datacenters/{datacenter:id}/clusters/{cluster:id}/enabledfeatures add
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks add
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks delete
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks get
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/activate activate
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/migrate migrate
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/stopmigrate stopmigrate
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id} delete
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id} get
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id}/replace replace
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id}/statistics statistics
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/glusterbricks/{glusterbrick:id}/statistics/{statistic:id} get
datacenters/{datacenter:id}/clusters/{cluster:id}/networkfilters get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/networks/{network:id}/networklabels add
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/networks/{network:id}/networklabels get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/networks/{network:id}/networklabels/{networklabel:id} delete
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/networks/{network:id}/networklabels/{networklabel:id} get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageserverconnections add
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageserverconnections get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageserverconnections/{storageserverconnection:id} delete
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageserverconnections/{storageserverconnection:id} get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageserverconnections/{storageserverconnection:id} update
datacenters/{datacenter:id}/storagedomains/{storagedomain:id}/disks/{disk:id}/register register
disks/{disk:id}/reduce reduce
externalvmimports add
groups/{group:id}/roles/{role:id} get
hosts/{host:id}/affinitylabels add
hosts/{host:id}/affinitylabels get
hosts/{host:id}/affinitylabels/{affinitylabel:id} delete
hosts/{host:id}/affinitylabels/{affinitylabel:id} get
hosts/{host:id}/externalnetworkproviderconfigurations get
hosts/{host:id}/nics/{nic:id}/networklabels add
hosts/{host:id}/nics/{nic:id}/networklabels get
hosts/{host:id}/nics/{nic:id}/networklabels/{networklabel:id} delete
hosts/{host:id}/nics/{nic:id}/networklabels/{networklabel:id} get
hosts/{host:id}/upgradecheck upgradecheck
imagetransfers add
imagetransfers get
imagetransfers/{imagetransfer:id} get
imagetransfers/{imagetransfer:id} delete
imagetransfers/{imagetransfer:id} update
imagetransfers/{imagetransfer:id}/cancel cancel
imagetransfers/{imagetransfer:id}/extend extend
imagetransfers/{imagetransfer:id}/finalize finalize
imagetransfers/{imagetransfer:id}/pause pause
imagetransfers/{imagetransfer:id}/resume resume
instancetypes/{instancetype:id}/nics/{nic:id} delete
networkfilters get
networkfilters/{networkfilter:id} get
networks/{network:id}/networklabels add
networks/{network:id}/networklabels get
networks/{network:id}/networklabels/{networklabel:id} delete
networks/{network:id}/networklabels/{networklabel:id} get
openstacknetworkproviders/{openstacknetworkprovider:id}/networks/{network:id}/import import
storagedomains/{storagedomain:id}/disks/{disk:id} update
storagedomains/{storagedomain:id}/disks/{disk:id}/reduce reduce
storagedomains/{storagedomain:id}/reduceluns reduceluns
storagedomains/{storagedomain:id}/updateovfstore updateovfstore
storagedomains/{storagedomain:id}/vms/{vm:id}/diskattachments get
templates/{template:id}/diskattachments get
templates/{template:id}/diskattachments/{diskattachment:id} delete
templates/{template:id}/diskattachments/{diskattachment:id} get
templates/{template:id}/nics/{nic:id} delete
users/{user:id}/groups get
users/{user:id}/roles/{role:id} get
vms/{vm:id}/affinitylabels add
vms/{vm:id}/affinitylabels get
vms/{vm:id}/affinitylabels/{affinitylabel:id} delete
vms/{vm:id}/affinitylabels/{affinitylabel:id} get
vms/{vm:id}/diskattachments add
vms/{vm:id}/diskattachments get
vms/{vm:id}/diskattachments/{diskattachment:id} delete
vms/{vm:id}/diskattachments/{diskattachment:id} get
vms/{vm:id}/diskattachments/{diskattachment:id} update
vms/{vm:id}/graphicsconsoles/{graphicsconsole:id}/proxyticket proxyticket
vms/{vm:id}/graphicsconsoles/{graphicsconsole:id}/remoteviewerconnectionfile remoteviewerconnectionfile
vms/{vm:id}/graphicsconsoles/{graphicsconsole:id}/ticket ticket
vms/{vm:id}/nics/{nic:id}/networkfilterparameters add
vms/{vm:id}/previewsnapshot previewsnapshot
vms/{vm:id}/undosnapshot undosnapshot

删除接口

接口 方法
capabilities get
capabilities/{capability:id} get
clusters/{cluster:id}/glustervolumes/{glustervolume:id} get response.type=GlusterVolumeProfileDetails
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks add
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks delete
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks get
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/activate activate
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/migrate migrate
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/stopmigrate stopmigrate
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id} delete
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id} get
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id}/replace replace
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id}/statistics get
clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id}/statistics/{statistic:id} get
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id} get response.type=GlusterVolumeProfileDetails
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks add
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks delete
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks get
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/activate activate
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/migrate migrate
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/stopmigrate stopmigrate
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id} delete
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id} get
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id}/replace replace
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id}/statistics statistics
datacenters/{datacenter:id}/clusters/{cluster:id}/glustervolumes/{glustervolume:id}/bricks/{brick:id}/statistics/{statistic:id} get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/networks/{network:id}/labels add
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/networks/{network:id}/labels get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/networks/{network:id}/labels/{label:id} delete
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/networks/{network:id}/labels/{label:id} get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageconnections add
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageconnections get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageconnections/{storageconnection:id} delete
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageconnections/{storageconnection:id} get
datacenters/{datacenter:id}/iscsibonds/{iscsibond:id}/storageconnections/{storageconnection:id} update
datacenters/{datacenter:id}/networks/{network:id}/labels add
datacenters/{datacenter:id}/networks/{network:id}/labels get
datacenters/{datacenter:id}/networks/{network:id}/labels/{label:id} delete
datacenters/{datacenter:id}/networks/{network:id}/labels/{label:id} get
datacenters/{datacenter:id}/networks/{network:id}/permissions add
datacenters/{datacenter:id}/networks/{network:id}/permissions/{permission:id} delete
datacenters/{datacenter:id}/networks/{network:id}/permissions/{permission:id} get
datacenters/{datacenter:id}/networks/{network:id}/vnicprofiles add
datacenters/{datacenter:id}/networks/{network:id}/vnicprofiles get
datacenters/{datacenter:id}/networks/{network:id}/vnicprofiles/{vnicprofile:id} delete
datacenters/{datacenter:id}/networks/{network:id}/vnicprofiles/{vnicprofile:id} get
datacenters/{datacenter:id}/networks/{network:id}/vnicprofiles/{vnicprofile:id}/permissions add
datacenters/{datacenter:id}/networks/{network:id}/vnicprofiles/{vnicprofile:id}/permissions get
datacenters/{datacenter:id}/networks/{network:id}/vnicprofiles/{vnicprofile:id}/permissions/{permission:id} delete
datacenters/{datacenter:id}/networks/{network:id}/vnicprofiles/{vnicprofile:id}/permissions/{permission:id} get
hosts/{host:id}/nics/{nic:id}/attach attach
hosts/{host:id}/nics/{nic:id}/detach detach
hosts/{host:id}/nics/{nic:id}/labels add
hosts/{host:id}/nics/{nic:id}/labels get
hosts/{host:id}/nics/{nic:id}/labels/{label:id} delete
hosts/{host:id}/nics/{nic:id}/labels/{label:id} get
networks/{network:id}/labels add
"networks/{network:id}/labels get
networks/{network:id}/labels/{label:id} delete
networks/{network:id}/labels/{label:id} get
templates/{template:id}/disks get
templates/{template:id}/disks/{disk:id} delete
templates/{template:id}/disks/{disk:id} get
templates/{template:id}/disks/{disk:id}/copy copy
templates/{template:id}/disks/{disk:id}/export export
vms/{vm:id}/commit_snapshot commit_snapshot
vms/{vm:id}/disks add
vms/{vm:id}/disks get
vms/{vm:id}/disks/{disk:id} get
vms/{vm:id}/disks/{disk:id} update
vms/{vm:id}/disks/{disk:id}/activate activate
vms/{vm:id}/disks/{disk:id}/deactivate deactivate
vms/{vm:id}/disks/{disk:id}/export export
vms/{vm:id}/disks/{disk:id}/move move
vms/{vm:id}/disks/{disk:id}/permissions add
vms/{vm:id}/disks/{disk:id}/permissions get
vms/{vm:id}/disks/{disk:id}/permissions/{permission:id} delete
vms/{vm:id}/disks/{disk:id}/permissions/{permission:id} get
vms/{vm:id}/disks/{disk:id}/statistics statistics
vms/{vm:id}/disks/{disk:id}/statistics/{statistic:id} get
vms/{vm:id}/preview_snapshot preview_snapshot
vms/{vm:id}/snapshots/{snapshot:id}/disks/{disk:id} delete
vms/{vm:id}/undo_snapshot undo_snapshot

修改接口

接口 方法 说明
clusters add 参数增加、删除、修改
clusters/{cluster:id} update 参数增加、删除、修改
datacenters add 参数删除
datacenters/{datacenter:id} delete 参数增加、删除
datacenters/{datacenter:id} update 参数删除
datacenters/{datacenter:id}/clusters add 参数增加、删除、修改
datacenters/{datacenter:id}/clusters/{cluster:id} update 参数增加、删除、修改
datacenters/{datacenter:id}/storagedomains/{storagedomain:id}/disks add 参数增加、删除、修改
disks add 参数增加、修改、删除
hosts add 参数增加、修改、删除
hosts/{host:id} delete 参数增加、删除
hosts/{host:id} get 参数删除
hosts/{host:id} update 参数删除
hosts/{host:id}/deactivate deactivate 参数增加
hosts/{host:id}/install install 参数增加
hosts/{host:id}/networkattachments add 参数增加
hosts/{host:id}/networkattachments/{networkattachment:id} update 参数增加
hosts/{host:id}/nics get 参数增加、删除、修改
hosts/{host:id}/nics add 参数增加、删除、修改
hosts/{host:id}/nics/{nic:id} get 参数增加、删除、修改
hosts/{host:id}/nics/{nic:id} update 参数增加、删除、修改
hosts/{host:id}/nics/{nic:id} delete 参数增加、删除、修改
storageconnections/{storageconnection:id} delete 参数增加、删除
storagedomains add 参数增加、删除、修改
storagedomains/{storagedomain:id} delete 参数增加、删除
storagedomains/{storagedomain:id} update 参数增加、删除、修改
storagedomains/{storagedomain:id}/disks add 参数增加、删除、修改
storagedomains/{storagedomain:id}/vms/{vm:id}/import import 参数增加、删除、修改
storagedomains/{storagedomain:id}/vms/{vm:id}/register register 参数增加
templates add 参数增加、删除、修改
templates/{template:id} update 参数增加、删除、修改
templates/{template:id}/nics add 参数删除
templates/{template:id}/nics/{nic:id} get 参数删除
users/{user:id}/tags/{tag:id} get 参数增加、修改
vmpools/{vmpool:id} update 参数增加、修改
vms add 参数增加、删除
vms/{vm:id} delete 参数增加、删除
vms/{vm:id} update 参数增加、删除
vms/{vm:id}/migrate migrate 参数增加、删除
vms/{vm:id}/nics add 参数删除
vms/{vm:id}/nics/{nic:id} update 参数删除
vms/{vm:id}/start start 参数增加、修改

相关文章

网友评论

    本文标题:【Ovirt 笔记】RestAPI 调用机制分析和整理

    本文链接:https://www.haomeiwen.com/subject/rtxzkqtx.html