Support k8s configmap grouped dynamic configurations (#7570)
* Support k8s configmap grouped dynamic configurations * Support single config read from multiple configmaps
This commit is contained in:
parent
944b47b515
commit
be0f57ae28
|
|
@ -48,6 +48,7 @@ Release Notes.
|
|||
* Support collection type in dynamic configuration core.
|
||||
* Support zookeeper grouped dynamic configurations.
|
||||
* Fix NPE when OAP nodes synchronize events with each other in cluster mode.
|
||||
* Support k8s configmap grouped dynamic configurations.
|
||||
|
||||
#### UI
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
package org.apache.skywalking.oap.server.configuration.configmap;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
@ -40,9 +40,9 @@ public class ConfigmapConfigurationWatcherRegister extends ConfigWatcherRegister
|
|||
@Override
|
||||
public Optional<ConfigTable> readConfig(Set<String> keys) {
|
||||
final ConfigTable configTable = new ConfigTable();
|
||||
Optional<V1ConfigMap> v1ConfigMap = informer.configMap();
|
||||
Map<String, String> configMapData = informer.configMapData();
|
||||
for (final String name : keys) {
|
||||
final String value = v1ConfigMap.map(V1ConfigMap::getData).map(data -> data.get(name)).orElse(null);
|
||||
final String value = configMapData.get(name);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("read config: name:{} ,value:{}", name, value);
|
||||
}
|
||||
|
|
@ -53,8 +53,19 @@ public class ConfigmapConfigurationWatcherRegister extends ConfigWatcherRegister
|
|||
|
||||
@Override
|
||||
public Optional<GroupConfigTable> readGroupConfig(final Set<String> keys) {
|
||||
// TODO: implement readGroupConfig
|
||||
return Optional.empty();
|
||||
}
|
||||
GroupConfigTable groupConfigTable = new GroupConfigTable();
|
||||
Map<String, String> configMapData = informer.configMapData();
|
||||
keys.forEach(key -> {
|
||||
GroupConfigTable.GroupConfigItems groupConfigItems = new GroupConfigTable.GroupConfigItems(key);
|
||||
groupConfigTable.addGroupConfigItems(groupConfigItems);
|
||||
configMapData.forEach((groupItemKey, itemValue) -> {
|
||||
if (groupItemKey.startsWith(key)) {
|
||||
String itemName = groupItemKey.replaceFirst(key + ".", "");
|
||||
groupConfigItems.add(new ConfigTable.ConfigItem(itemName, itemValue));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return Optional.of(groupConfigTable);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ import io.kubernetes.client.openapi.models.V1ConfigMap;
|
|||
import io.kubernetes.client.openapi.models.V1ConfigMapList;
|
||||
import io.kubernetes.client.util.Config;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
|
@ -37,7 +38,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||
|
||||
@Slf4j
|
||||
public class ConfigurationConfigmapInformer {
|
||||
|
||||
private Lister<V1ConfigMap> configMapLister;
|
||||
|
||||
private SharedInformerFactory factory;
|
||||
|
|
@ -84,8 +84,18 @@ public class ConfigurationConfigmapInformer {
|
|||
configMapLister = new Lister<>(configMapSharedIndexInformer.getIndexer());
|
||||
}
|
||||
|
||||
public Optional<V1ConfigMap> configMap() {
|
||||
return Optional.ofNullable(configMapLister.list().size() == 1 ? configMapLister.list().get(0) : null);
|
||||
}
|
||||
public Map<String, String> configMapData() {
|
||||
Map<String, String> configMapData = new HashMap<>();
|
||||
if (configMapLister != null && configMapLister.list() != null) {
|
||||
configMapLister.list().forEach(cf -> {
|
||||
Map<String, String> data = cf.getData();
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
configMapData.putAll(data);
|
||||
});
|
||||
}
|
||||
|
||||
return configMapData;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@
|
|||
|
||||
package org.apache.skywalking.oap.server.configuration.configmap;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMap;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.Reader;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -27,6 +28,7 @@ import java.util.Objects;
|
|||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.skywalking.oap.server.configuration.api.ConfigTable;
|
||||
import org.apache.skywalking.oap.server.configuration.api.GroupConfigTable;
|
||||
import org.apache.skywalking.oap.server.library.util.ResourceUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
|
@ -59,8 +61,8 @@ public class ConfigmapConfigWatcherRegisterTest {
|
|||
|
||||
@Test
|
||||
public void readConfigWhenConfigMapDataIsNull() throws Exception {
|
||||
V1ConfigMap v1ConfigMap = new V1ConfigMap();
|
||||
PowerMockito.doReturn(Optional.of(v1ConfigMap)).when(informer).configMap();
|
||||
Map<String, String> configMapData = new HashMap<>();
|
||||
PowerMockito.doReturn(configMapData).when(informer).configMapData();
|
||||
Optional<ConfigTable> optionalConfigTable = register.readConfig(new HashSet<String>() {{
|
||||
add("key1");
|
||||
}});
|
||||
|
|
@ -74,7 +76,7 @@ public class ConfigmapConfigWatcherRegisterTest {
|
|||
|
||||
@Test
|
||||
public void readConfigWhenInformerNotwork() throws Exception {
|
||||
PowerMockito.doReturn(Optional.empty()).when(informer).configMap();
|
||||
PowerMockito.doReturn(new HashMap<>()).when(informer).configMapData();
|
||||
Optional<ConfigTable> optionalConfigTable = register.readConfig(new HashSet<String>() {{
|
||||
add("key1");
|
||||
}});
|
||||
|
|
@ -88,17 +90,15 @@ public class ConfigmapConfigWatcherRegisterTest {
|
|||
|
||||
@Test
|
||||
public void readConfigWhenInformerWork() throws Exception {
|
||||
Reader configmapReader = ResourceUtils.read("skywalking-dynamic-configmap.example.yaml");
|
||||
Map<String, Map<String, String>> configmapMap = yaml.loadAs(configmapReader, Map.class);
|
||||
V1ConfigMap v1ConfigMap = new V1ConfigMap();
|
||||
v1ConfigMap.data(configmapMap.get("data"));
|
||||
PowerMockito.doReturn(Optional.of(v1ConfigMap)).when(informer).configMap();
|
||||
Map<String, String> configMapData = this.readMockConfigMapData();
|
||||
PowerMockito.doReturn(configMapData).when(informer).configMapData();
|
||||
Optional<ConfigTable> optionalConfigTable = register.readConfig(new HashSet<String>() {{
|
||||
add("receiver-trace.default.slowDBAccessThreshold");
|
||||
add("alarm.default.alarm-settings");
|
||||
add("core.default.apdexThreshold");
|
||||
add("receiver-trace.default.uninstrumentedGateways");
|
||||
}});
|
||||
|
||||
Assert.assertTrue(optionalConfigTable.isPresent());
|
||||
ConfigTable configTable = optionalConfigTable.get();
|
||||
|
||||
|
|
@ -108,4 +108,65 @@ public class ConfigmapConfigWatcherRegisterTest {
|
|||
.collect(Collectors.toList());
|
||||
Assert.assertEquals(list.size(), 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readGroupConfigWhenConfigMapDataIsNull() throws Exception {
|
||||
Map<String, String> configMapData = new HashMap<>();
|
||||
PowerMockito.doReturn(configMapData).when(informer).configMapData();
|
||||
Optional<GroupConfigTable> optionalGroupConfigTable = register.readGroupConfig(new HashSet<String>() {{
|
||||
add("key1");
|
||||
}});
|
||||
|
||||
Assert.assertTrue(optionalGroupConfigTable.isPresent());
|
||||
GroupConfigTable groupConfigTable = optionalGroupConfigTable.get();
|
||||
Assert.assertEquals(groupConfigTable.getGroupItems().size(), 1);
|
||||
Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getName(), "key1");
|
||||
Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getItems().size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readGroupConfigWhenInformerNotwork() throws Exception {
|
||||
PowerMockito.doReturn(new HashMap<>()).when(informer).configMapData();
|
||||
Optional<GroupConfigTable> optionalGroupConfigTable = register.readGroupConfig(new HashSet<String>() {{
|
||||
add("key1");
|
||||
}});
|
||||
|
||||
Assert.assertTrue(optionalGroupConfigTable.isPresent());
|
||||
GroupConfigTable groupConfigTable = optionalGroupConfigTable.get();
|
||||
Assert.assertEquals(groupConfigTable.getGroupItems().size(), 1);
|
||||
Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getName(), "key1");
|
||||
Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getItems().size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readGroupConfigWhenInformerWork() throws Exception {
|
||||
Map<String, String> configMapData = this.readMockConfigMapData();
|
||||
PowerMockito.doReturn(configMapData).when(informer).configMapData();
|
||||
Optional<GroupConfigTable> optionalGroupConfigTable = register.readGroupConfig(new HashSet<String>() {{
|
||||
add("core.default.endpoint-name-grouping-openapi");
|
||||
}});
|
||||
|
||||
Assert.assertTrue(optionalGroupConfigTable.isPresent());
|
||||
GroupConfigTable groupConfigTable = optionalGroupConfigTable.get();
|
||||
|
||||
Assert.assertEquals(groupConfigTable.getGroupItems().size(), 1);
|
||||
Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getName(), "core.default.endpoint-name-grouping-openapi");
|
||||
Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getItems().size(), 3);
|
||||
}
|
||||
|
||||
private Map<String, String> readMockConfigMapData() throws FileNotFoundException {
|
||||
Reader configmapReader1 = ResourceUtils.read("skywalking-dynamic-configmap.example.yaml");
|
||||
Reader configmapReader2 = ResourceUtils.read("skywalking-group-dynamic-configmap.example-serviceA.yaml");
|
||||
Reader configmapReader3 = ResourceUtils.read("skywalking-group-dynamic-configmap.example-serviceB.yaml");
|
||||
Map<String, Map<String, String>> configmapMap1 = yaml.loadAs(configmapReader1, Map.class);
|
||||
Map<String, Map<String, String>> configmapMap2 = yaml.loadAs(configmapReader2, Map.class);
|
||||
Map<String, Map<String, String>> configmapMap3 = yaml.loadAs(configmapReader3, Map.class);
|
||||
|
||||
Map<String, String> configMapData = new HashMap<>();
|
||||
configMapData.putAll(configmapMap1.get("data"));
|
||||
configMapData.putAll(configmapMap2.get("data"));
|
||||
configMapData.putAll(configmapMap3.get("data"));
|
||||
|
||||
return configMapData;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ kind: ConfigMap
|
|||
metadata:
|
||||
name: skywalking-dynamic-config
|
||||
labels:
|
||||
app: skywalking-alarm
|
||||
app: collector
|
||||
release: skywalking
|
||||
data:
|
||||
receiver-trace.default.slowDBAccessThreshold: default:200,mongodb:50
|
||||
|
|
|
|||
|
|
@ -0,0 +1,348 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
#
|
||||
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: skywalking-dynamic-config2
|
||||
labels:
|
||||
app: collector
|
||||
release: skywalking
|
||||
data:
|
||||
core.default.endpoint-name-grouping-openapi.customerAPI-v1.yaml: |-
|
||||
openapi: 3.0.0
|
||||
x-sw-service-name: serviceA
|
||||
info:
|
||||
description: OpenAPI definition for SkyWalking test.
|
||||
version: v1
|
||||
title: Customer API
|
||||
|
||||
tags:
|
||||
- name: customer
|
||||
description: customer
|
||||
|
||||
paths:
|
||||
/customers:
|
||||
get:
|
||||
tags:
|
||||
- customer
|
||||
summary: Get all customers list
|
||||
description: Get all customers list.
|
||||
operationId: getCustomers
|
||||
responses:
|
||||
"200":
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Customer"
|
||||
/customers/{id}:
|
||||
get:
|
||||
tags:
|
||||
- customer
|
||||
summary: Get customer details
|
||||
description: Get customer details with the given id.
|
||||
operationId: getCustomer
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Customer id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CustomerDetails"
|
||||
"400":
|
||||
description: Invalid customer id
|
||||
post:
|
||||
tags:
|
||||
- customer
|
||||
summary: Update customer details
|
||||
description: Update customer details with the given id.
|
||||
operationId: updateCustomer
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Customer id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
- name: name
|
||||
in: query
|
||||
description: Customer name
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
delete:
|
||||
tags:
|
||||
- customer
|
||||
summary: Delete customer details
|
||||
description: Delete customer details with the given id.
|
||||
operationId: deleteCustomer
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Customer id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
|
||||
/customer/{region}/{country}:
|
||||
get:
|
||||
tags:
|
||||
- customer
|
||||
summary: Get customers regional
|
||||
description: Get customers regional with the given id.
|
||||
operationId: getCustomersRegional
|
||||
parameters:
|
||||
- name: region
|
||||
in: path
|
||||
description: Customers region
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: country
|
||||
in: path
|
||||
description: Customers country
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Customer"
|
||||
"400":
|
||||
description: Invalid parameters supplied
|
||||
components:
|
||||
schemas:
|
||||
Customer:
|
||||
type: object
|
||||
description: Customer id and name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Customer id
|
||||
name:
|
||||
type: string
|
||||
description: Customer name
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
CustomerDetails:
|
||||
type: object
|
||||
description: Customer details
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Customer id
|
||||
name:
|
||||
type: string
|
||||
description: Customer name
|
||||
description:
|
||||
type: string
|
||||
description: Customer description
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
core.default.endpoint-name-grouping-openapi.productAPI-v1.yaml: |-
|
||||
openapi: 3.0.0
|
||||
x-sw-service-name: serviceA
|
||||
info:
|
||||
description: OpenAPI definition for SkyWalking test.
|
||||
version: v1
|
||||
title: Product API
|
||||
|
||||
tags:
|
||||
- name: product
|
||||
description: product
|
||||
- name: relatedProducts
|
||||
description: Related Products
|
||||
|
||||
paths:
|
||||
/products:
|
||||
get:
|
||||
tags:
|
||||
- product
|
||||
summary: Get all products list
|
||||
description: Get all products list.
|
||||
operationId: getProducts
|
||||
responses:
|
||||
"200":
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Product"
|
||||
/products/{id}:
|
||||
get:
|
||||
tags:
|
||||
- product
|
||||
summary: Get product details
|
||||
description: Get product details with the given id.
|
||||
operationId: getProduct
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Product id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ProductDetails"
|
||||
"400":
|
||||
description: Invalid product id
|
||||
post:
|
||||
tags:
|
||||
- product
|
||||
summary: Update product details
|
||||
description: Update product details with the given id.
|
||||
operationId: updateProduct
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Product id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
- name: name
|
||||
in: query
|
||||
description: Product name
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
delete:
|
||||
tags:
|
||||
- product
|
||||
summary: Delete product details
|
||||
description: Delete product details with the given id.
|
||||
operationId: deleteProduct
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Product id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
/products/{id}/relatedProducts:
|
||||
get:
|
||||
tags:
|
||||
- relatedProducts
|
||||
summary: Get related products
|
||||
description: Get related products with the given product id.
|
||||
operationId: getRelatedProducts
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Product id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/RelatedProducts"
|
||||
"400":
|
||||
description: Invalid product id
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Product:
|
||||
type: object
|
||||
description: Product id and name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Product id
|
||||
name:
|
||||
type: string
|
||||
description: Product name
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
ProductDetails:
|
||||
type: object
|
||||
description: Product details
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Product id
|
||||
name:
|
||||
type: string
|
||||
description: Product name
|
||||
description:
|
||||
type: string
|
||||
description: Product description
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
RelatedProducts:
|
||||
type: object
|
||||
description: Related Products
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Product id
|
||||
relatedProducts:
|
||||
type: array
|
||||
description: List of related products
|
||||
items:
|
||||
$ref: "#/components/schemas/Product"
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
#
|
||||
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: skywalking-dynamic-config3
|
||||
labels:
|
||||
app: collector
|
||||
release: skywalking
|
||||
data:
|
||||
core.default.endpoint-name-grouping-openapi.productAPI-v2.yaml: |-
|
||||
openapi: 3.0.0
|
||||
x-sw-service-name: serviceB
|
||||
info:
|
||||
description: OpenAPI definition for SkyWalking test.
|
||||
version: v2
|
||||
title: Product API
|
||||
|
||||
tags:
|
||||
- name: product
|
||||
description: product
|
||||
- name: relatedProducts
|
||||
description: Related Products
|
||||
|
||||
paths:
|
||||
/products:
|
||||
get:
|
||||
tags:
|
||||
- product
|
||||
summary: Get all products list
|
||||
description: Get all products list.
|
||||
operationId: getProducts
|
||||
responses:
|
||||
"200":
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Product"
|
||||
/products/{region}/{country}:
|
||||
get:
|
||||
tags:
|
||||
- product
|
||||
summary: Get products regional
|
||||
description: Get products regional with the given id.
|
||||
operationId: getProductRegional
|
||||
parameters:
|
||||
- name: region
|
||||
in: path
|
||||
description: Products region
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: country
|
||||
in: path
|
||||
description: Products country
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Product"
|
||||
"400":
|
||||
description: Invalid parameters supplied
|
||||
/products/{id}:
|
||||
get:
|
||||
tags:
|
||||
- product
|
||||
summary: Get product details
|
||||
description: Get product details with the given id.
|
||||
operationId: getProduct
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Product id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ProductDetails"
|
||||
"400":
|
||||
description: Invalid product id
|
||||
post:
|
||||
tags:
|
||||
- product
|
||||
summary: Update product details
|
||||
description: Update product details with the given id.
|
||||
operationId: updateProduct
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Product id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
- name: name
|
||||
in: query
|
||||
description: Product name
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
delete:
|
||||
tags:
|
||||
- product
|
||||
summary: Delete product details
|
||||
description: Delete product details with the given id.
|
||||
operationId: deleteProduct
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Product id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
/products/{id}/relatedProducts:
|
||||
get:
|
||||
tags:
|
||||
- relatedProducts
|
||||
summary: Get related products
|
||||
description: Get related products with the given product id.
|
||||
operationId: getRelatedProducts
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: Product id
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/RelatedProducts"
|
||||
"400":
|
||||
description: Invalid product id
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Product:
|
||||
type: object
|
||||
description: Product id and name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Product id
|
||||
name:
|
||||
type: string
|
||||
description: Product name
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
ProductDetails:
|
||||
type: object
|
||||
description: Product details
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Product id
|
||||
name:
|
||||
type: string
|
||||
description: Product name
|
||||
description:
|
||||
type: string
|
||||
description: Product description
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
RelatedProducts:
|
||||
type: object
|
||||
description: Related Products
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Product id
|
||||
relatedProducts:
|
||||
type: array
|
||||
description: List of related products
|
||||
items:
|
||||
$ref: "#/components/schemas/Product"
|
||||
Loading…
Reference in New Issue