----初始化项目

This commit is contained in:
2025-09-19 20:49:14 +08:00
parent b345d2828d
commit df7765c400
2867 changed files with 359313 additions and 89 deletions

142
istio/pom.xml Normal file
View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2018 Alibaba Group Holding Ltd.
~
~ Licensed 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>nacos-all</artifactId>
<groupId>com.alibaba.nacos</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-istio</artifactId>
<packaging>jar</packaging>
<name>nacos-istio ${project.version}</name>
<url>https://nacos.io</url>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-api</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-config</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-naming</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-core</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
</dependency>
<dependency>
<groupId>com.google.api.grpc</groupId>
<artifactId>proto-google-common-protos</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency>
<dependency>
<groupId>io.envoyproxy.controlplane</groupId>
<artifactId>api</artifactId>
<version>0.1.27</version>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.5.0.Final</version>
</extension>
</extensions>
<plugins>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.alibaba.nacos.istio.IstioApp</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<pluginId>grpc-java</pluginId>
<protocArtifact>com.google.protobuf:protoc:${protobuf-java.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${protoc-gen-grpc-java.version}:exe:${os.detected.classifier}</pluginArtifact>
<useArgumentFile>true</useArgumentFile>
<checkStaleness>true</checkStaleness>
<staleMillis>10000</staleMillis>
<protoSourceRoot>src/main/resources/proto</protoSourceRoot>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,36 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* Istio starter.
*
* @author nkorange
* @since 1.1.4
*/
@EnableScheduling
@SpringBootApplication
public class IstioApp {
public static void main(String[] args) {
SpringApplication.run(IstioApp.class, args);
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.api;
/**
* @author special.fy
*/
public class ApiConstants {
/**
* Default api prefix of any type of google protocol buffer.
*/
public static final String API_TYPE_PREFIX = "type.googleapis.com/";
/**
* Istio crd type url for mcp over xds
* TODO Support other Istio crd, such as gateway, vs, dr and so on.
*/
public static final String SERVICE_ENTRY_PROTO_PACKAGE = "networking.istio.io/v1alpha3/ServiceEntry";
public static final String MESH_CONFIG_PROTO_PACKAGE = "core/v1alpha1/MeshConfig";
/**
* Istio crd type url for mcp
*/
public static final String MCP_PREFIX = "istio/";
public static final String SERVICE_ENTRY_COLLECTION = MCP_PREFIX + "networking/v1alpha3/serviceentries";
/**
* Istio crd type url of api.
*/
public static final String MCP_RESOURCE_PROTO = API_TYPE_PREFIX + "istio.mcp.v1alpha1.Resource";
public static final String SERVICE_ENTRY_PROTO = API_TYPE_PREFIX + "istio.networking.v1alpha3.ServiceEntry";
/**
* Standard xds type url
* TODO Support lds, rds and sds
*/
public static final String CLUSTER_TYPE = API_TYPE_PREFIX + "envoy.config.cluster.v3.Cluster";
public static final String ENDPOINT_TYPE = API_TYPE_PREFIX + "envoy.config.endpoint.v3.ClusterLoadAssignment";
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.api;
import com.alibaba.nacos.istio.common.ResourceSnapshot;
import java.util.List;
/**
* This interface is used to generator mcp resources or xds data.
*
* @author special.fy
*/
public interface ApiGenerator<T> {
/**
* Generate data based on resource snapshot.
*
* @param resourceSnapshot Resource snapshot
* @return data
*/
List<T> generate(ResourceSnapshot resourceSnapshot);
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.api;
import com.alibaba.nacos.istio.mcp.EmptyMcpGenerator;
import com.alibaba.nacos.istio.mcp.ServiceEntryMcpGenerator;
import com.alibaba.nacos.istio.xds.EmptyXdsGenerator;
import com.alibaba.nacos.istio.xds.ServiceEntryXdsGenerator;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import static com.alibaba.nacos.istio.api.ApiConstants.*;
/**
* @author special.fy
*/
@Component
public class ApiGeneratorFactory {
private final Map<String, ApiGenerator<?>> apiGeneratorMap;
public ApiGeneratorFactory() {
apiGeneratorMap = new HashMap<>(2);
// mcp over xds
apiGeneratorMap.put(SERVICE_ENTRY_PROTO_PACKAGE, ServiceEntryXdsGenerator.getInstance());
// TODO Support other api generator
// mcp
apiGeneratorMap.put(SERVICE_ENTRY_COLLECTION, ServiceEntryMcpGenerator.getInstance());
}
public ApiGenerator<?> getApiGenerator(String typeUrl) {
ApiGenerator<?> apiGenerator = apiGeneratorMap.get(typeUrl);
return apiGenerator != null ? apiGenerator :
(typeUrl.startsWith(MCP_PREFIX) ? EmptyMcpGenerator.getInstance() : EmptyXdsGenerator.getInstance());
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.common;
import io.grpc.stub.StreamObserver;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
* AbstractConnection maintains the life cycle of the connection.
*
* @author special.fy
*/
public abstract class AbstractConnection<MessageT> {
private static AtomicLong connectIdGenerator = new AtomicLong(0);
private String connectionId;
protected StreamObserver<MessageT> streamObserver;
private final Map<String, WatchedStatus> watchedResources;
public AbstractConnection(StreamObserver<MessageT> streamObserver) {
this.streamObserver = streamObserver;
this.watchedResources = new HashMap<>(1 << 4);
}
public void setConnectionId(String clientId) {
long id = connectIdGenerator.getAndIncrement();
this.connectionId = clientId + "-" + id;
}
public String getConnectionId() {
return connectionId;
}
public void addWatchedResource(String resourceType, WatchedStatus watchedStatus) {
watchedResources.put(resourceType, watchedStatus);
}
public WatchedStatus getWatchedStatusByType(String resourceType) {
return watchedResources.get(resourceType);
}
/**
* Push data to grpc connection.
*
* @param message response
* @param watchedStatus watched status
*/
public abstract void push(MessageT message, WatchedStatus watchedStatus);
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.common;
/**
* @author special.fy
*/
public class Event {
public static final Event SERVICE_UPDATE_EVENT = new Event(EventType.Service);
private EventType type;
public Event(EventType type) {
this.type = type;
}
public EventType getType() {
return type;
}
public void setType(EventType type) {
this.type = type;
}
}

View File

@ -0,0 +1,158 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.common;
import com.alibaba.nacos.istio.mcp.NacosMcpService;
import com.alibaba.nacos.istio.misc.Loggers;
import com.alibaba.nacos.istio.util.IstioExecutor;
import com.alibaba.nacos.istio.xds.NacosXdsService;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* EventProcessor.
*
* @author special.fy
*/
@Component
public class EventProcessor implements ApplicationListener<ContextRefreshedEvent> {
private static final int MAX_WAIT_EVENT_TIME = 100;
private NacosMcpService nacosMcpService;
private NacosXdsService nacosXdsService;
private NacosResourceManager resourceManager;
private final BlockingQueue<Event> events;
public EventProcessor() {
events = new ArrayBlockingQueue<>(20);
}
/**
* notify.
*
* @param event event
*/
public void notify(Event event) {
try {
events.put(event);
} catch (InterruptedException e) {
Loggers.MAIN.warn("There are too many events, this event {} will be ignored.", event.getType());
// set the interrupted flag
Thread.currentThread().interrupt();
}
}
private void handleEvents() {
Consumer handleEvents = new Consumer("handle events");
handleEvents.setDaemon(true);
handleEvents.start();
}
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
if (contextRefreshedEvent.getApplicationContext().getParent() == null) {
checkDependenceReady();
handleEvents();
}
}
private class Consumer extends Thread {
Consumer(String name) {
setName(name);
}
@Override
@SuppressWarnings("InfiniteLoopStatement")
public void run() {
Future<Void> task = null;
boolean hasNewEvent = false;
Event lastEvent = null;
while (true) {
try {
// Today we only care about service event,
// so we simply ignore event until the last task has been completed.
Event event = events.poll(MAX_WAIT_EVENT_TIME, TimeUnit.MILLISECONDS);
if (event != null) {
hasNewEvent = true;
lastEvent = event;
}
if (hasClientConnection() && needNewTask(hasNewEvent, task)) {
task = IstioExecutor.asyncHandleEvent(new EventHandleTask(lastEvent));
hasNewEvent = false;
lastEvent = null;
}
} catch (InterruptedException e) {
Loggers.MAIN.warn("Thread {} is be interrupted.", getName());
// set the interrupted flag
Thread.currentThread().interrupt();
}
}
}
}
private boolean hasClientConnection() {
return nacosMcpService.hasClientConnection() || nacosXdsService.hasClientConnection();
}
private boolean needNewTask(boolean hasNewEvent, Future<Void> task) {
return hasNewEvent && (task == null || task.isDone());
}
private class EventHandleTask implements Callable<Void> {
private final Event event;
EventHandleTask(Event event) {
this.event = event;
}
@Override
public Void call() throws Exception {
ResourceSnapshot snapshot = resourceManager.createResourceSnapshot();
nacosXdsService.handleEvent(snapshot, event);
nacosMcpService.handleEvent(snapshot, event);
return null;
}
}
private boolean checkDependenceReady() {
if (null == resourceManager) {
resourceManager = ApplicationUtils.getBean(NacosResourceManager.class);
}
if (null == nacosXdsService) {
nacosXdsService = ApplicationUtils.getBean(NacosXdsService.class);
}
if (null == nacosMcpService) {
nacosMcpService = ApplicationUtils.getBean(NacosMcpService.class);
}
return Objects.nonNull(resourceManager) && Objects.nonNull(nacosMcpService) && Objects.nonNull(nacosXdsService);
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.common;
/**
* @author special.fy
*/
public enum EventType {
/**
* The service info of nacos changes.
*/
Service,
/**
* The endpoints of service change.
*/
Endpoint;
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.common;
import com.alibaba.nacos.istio.misc.IstioConfig;
import com.alibaba.nacos.istio.model.IstioService;
import com.alibaba.nacos.istio.util.IstioExecutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author special.fy
*/
@Component
public class NacosResourceManager {
private ResourceSnapshot resourceSnapshot;
@Autowired
NacosServiceInfoResourceWatcher serviceInfoResourceWatcher;
@Autowired
private IstioConfig istioConfig;
public NacosResourceManager() {
resourceSnapshot = new ResourceSnapshot();
}
public void start() {
IstioExecutor.registerNacosResourceWatcher(serviceInfoResourceWatcher, istioConfig.getMcpPushInterval() * 2L,
istioConfig.getMcpPushInterval());
}
public Map<String, IstioService> services() {
return serviceInfoResourceWatcher.snapshot();
}
public IstioConfig getIstioConfig() {
return istioConfig;
}
public synchronized ResourceSnapshot getResourceSnapshot() {
return resourceSnapshot;
}
public synchronized void setResourceSnapshot(ResourceSnapshot resourceSnapshot) {
this.resourceSnapshot = resourceSnapshot;
}
public void initResourceSnapshot() {
ResourceSnapshot resourceSnapshot = getResourceSnapshot();
resourceSnapshot.initResourceSnapshot(this);
}
public ResourceSnapshot createResourceSnapshot() {
ResourceSnapshot resourceSnapshot = new ResourceSnapshot();
resourceSnapshot.initResourceSnapshot(this);
setResourceSnapshot(resourceSnapshot);
return resourceSnapshot;
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.common;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.istio.model.IstioService;
import com.alibaba.nacos.istio.util.IstioCrdUtil;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author special.fy
*/
@org.springframework.stereotype.Service
public class NacosServiceInfoResourceWatcher implements Runnable {
private final Map<String, IstioService> serviceInfoMap = new ConcurrentHashMap<>(16);
@Autowired
private ServiceStorage serviceStorage;
@Autowired
private EventProcessor eventProcessor;
@Override
public void run() {
boolean changed = false;
// Query all services to see if any of them have changes.
Set<String> namespaces = ServiceManager.getInstance().getAllNamespaces();
Set<String> allServices = new HashSet<>();
for (String namespace : namespaces) {
Set<Service> services = ServiceManager.getInstance().getSingletons(namespace);
if (services.isEmpty()) {
continue;
}
for (Service service : services) {
String serviceName = IstioCrdUtil.buildServiceNameForServiceEntry(service);
allServices.add(serviceName);
IstioService old = serviceInfoMap.get(serviceName);
// Service not changed
if (old != null && old.getRevision().equals(service.getRevision())) {
continue;
}
// Update the resource
changed = true;
ServiceInfo serviceInfo = serviceStorage.getPushData(service);
if (!serviceInfo.isValid()) {
serviceInfoMap.remove(serviceName);
continue;
}
if (old != null) {
serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo, old));
} else {
serviceInfoMap.put(serviceName, new IstioService(service, serviceInfo));
}
}
}
for (String key : serviceInfoMap.keySet()) {
if (!allServices.contains(key)) {
changed = true;
serviceInfoMap.remove(key);
}
}
if (changed) {
eventProcessor.notify(Event.SERVICE_UPDATE_EVENT);
}
}
public Map<String, IstioService> snapshot() {
return new HashMap<>(serviceInfoMap);
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.common;
import com.alibaba.nacos.istio.model.IstioService;
import com.alibaba.nacos.istio.model.ServiceEntryWrapper;
import com.alibaba.nacos.istio.util.IstioCrdUtil;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author special.fy
*/
public class ResourceSnapshot {
private static AtomicLong versionSuffix = new AtomicLong(0);
private final List<ServiceEntryWrapper> serviceEntries;
private boolean isCompleted;
private String version;
public ResourceSnapshot() {
isCompleted = false;
serviceEntries = new ArrayList<>();
}
public synchronized void initResourceSnapshot(NacosResourceManager manager) {
if (isCompleted) {
return;
}
initServiceEntry(manager);
generateVersion();
isCompleted = true;
}
private void generateVersion() {
String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date());
version = time + "/" + versionSuffix.getAndIncrement();
}
private void initServiceEntry(NacosResourceManager manager) {
Map<String, IstioService> serviceInfoMap = manager.services();
for (String serviceName : serviceInfoMap.keySet()) {
ServiceEntryWrapper serviceEntryWrapper = IstioCrdUtil.buildServiceEntry(serviceName, manager.getIstioConfig().getDomainSuffix(), serviceInfoMap.get(serviceName));
if (serviceEntryWrapper != null) {
serviceEntries.add(serviceEntryWrapper);
}
}
}
public List<ServiceEntryWrapper> getServiceEntries() {
return serviceEntries;
}
public boolean isCompleted() {
return isCompleted;
}
public String getVersion() {
return version;
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.common;
/**
* @author special.fy
*/
public class WatchedStatus {
private String type;
private String latestVersion;
private String latestNonce;
private String ackedVersion;
private String ackedNonce;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getLatestVersion() {
return latestVersion;
}
public void setLatestVersion(String latestVersion) {
this.latestVersion = latestVersion;
}
public String getLatestNonce() {
return latestNonce;
}
public void setLatestNonce(String latestNonce) {
this.latestNonce = latestNonce;
}
public String getAckedVersion() {
return ackedVersion;
}
public void setAckedVersion(String ackedVersion) {
this.ackedVersion = ackedVersion;
}
public String getAckedNonce() {
return ackedNonce;
}
public void setAckedNonce(String ackedNonce) {
this.ackedNonce = ackedNonce;
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.config;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.istio.IstioApp;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.filter.NacosPackageExcludeFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
import static com.alibaba.nacos.sys.env.EnvUtil.FUNCTION_MODE_NAMING;
/**
* Istio module enabled filter by spring packages scan.
*
* @author xiweng.yy
*/
public class IstioEnabledFilter implements NacosPackageExcludeFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(IstioEnabledFilter.class);
private static final String ISTIO_ENABLED_KEY = "nacos.extension.naming.istio.enabled";
@Override
public String getResponsiblePackagePrefix() {
return IstioApp.class.getPackage().getName();
}
@Override
public boolean isExcluded(String className, Set<String> annotationNames) {
String functionMode = EnvUtil.getFunctionMode();
// When not specified naming mode or specified all mode, the naming module not start and load.
if (isNamingDisabled(functionMode)) {
LOGGER.warn("Istio module disabled because function mode is {}, and Istio depend naming module",
functionMode);
return true;
}
boolean istioDisabled = !EnvUtil.getProperty(ISTIO_ENABLED_KEY, Boolean.class, false);
if (istioDisabled) {
LOGGER.warn("Istio module disabled because set {} as false", ISTIO_ENABLED_KEY);
}
return istioDisabled;
}
private boolean isNamingDisabled(String functionMode) {
if (StringUtils.isEmpty(functionMode)) {
return false;
}
return !FUNCTION_MODE_NAMING.equals(functionMode);
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.mcp;
import com.alibaba.nacos.istio.api.ApiGenerator;
import com.alibaba.nacos.istio.common.ResourceSnapshot;
import istio.mcp.v1alpha1.ResourceOuterClass.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author special.fy
*/
public class EmptyMcpGenerator implements ApiGenerator<Resource> {
private volatile static EmptyMcpGenerator singleton = null;
public static EmptyMcpGenerator getInstance() {
if (singleton == null) {
synchronized (EmptyMcpGenerator.class) {
if (singleton == null) {
singleton = new EmptyMcpGenerator();
}
}
}
return singleton;
}
@Override
public List<Resource> generate(ResourceSnapshot resourceSnapshot) {
return new ArrayList<>();
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.mcp;
import com.alibaba.nacos.istio.common.AbstractConnection;
import com.alibaba.nacos.istio.common.WatchedStatus;
import com.alibaba.nacos.istio.misc.Loggers;
import io.grpc.stub.StreamObserver;
import istio.mcp.v1alpha1.Mcp;
/**
* @author special.fy
*/
public class McpConnection extends AbstractConnection<Mcp.Resources> {
public McpConnection(StreamObserver<Mcp.Resources> streamObserver) {
super(streamObserver);
}
@Override
public synchronized void push(Mcp.Resources response, WatchedStatus watchedStatus) {
if (Loggers.MAIN.isDebugEnabled()) {
Loggers.MAIN.debug("Mcp.Resources: {}", response.toString());
}
this.streamObserver.onNext(response);
// Update watched status
watchedStatus.setLatestVersion(response.getSystemVersionInfo());
watchedStatus.setLatestNonce(response.getNonce());
Loggers.MAIN.info("mcp: push, type: {}, connection-id {}, version {}, nonce {}, resource size {}.",
watchedStatus.getType(),
getConnectionId(),
response.getSystemVersionInfo(),
response.getNonce(),
response.getResourcesCount());
}
}

View File

@ -0,0 +1,194 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.mcp;
import com.alibaba.nacos.istio.api.ApiGenerator;
import com.alibaba.nacos.istio.api.ApiGeneratorFactory;
import com.alibaba.nacos.istio.common.AbstractConnection;
import com.alibaba.nacos.istio.common.Event;
import com.alibaba.nacos.istio.common.NacosResourceManager;
import com.alibaba.nacos.istio.common.ResourceSnapshot;
import com.alibaba.nacos.istio.common.WatchedStatus;
import com.alibaba.nacos.istio.misc.Loggers;
import com.alibaba.nacos.istio.util.NonceGenerator;
import io.grpc.stub.StreamObserver;
import istio.mcp.v1alpha1.Mcp;
import istio.mcp.v1alpha1.ResourceOuterClass.Resource;
import istio.mcp.v1alpha1.ResourceSourceGrpc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.alibaba.nacos.istio.api.ApiConstants.SERVICE_ENTRY_COLLECTION;
/**
* nacos mcp service.
*
* @author nkorange
* @since 1.1.4
*/
@Service
public class NacosMcpService extends ResourceSourceGrpc.ResourceSourceImplBase {
private final Map<String, AbstractConnection<Mcp.Resources>> connections = new ConcurrentHashMap<>(16);
@Autowired
ApiGeneratorFactory apiGeneratorFactory;
@Autowired
NacosResourceManager resourceManager;
public boolean hasClientConnection() {
return connections.size() != 0;
}
@Override
public StreamObserver<Mcp.RequestResources> establishResourceStream(StreamObserver<Mcp.Resources> responseObserver) {
// TODO add authN
// Init snapshot of nacos service info.
resourceManager.initResourceSnapshot();
AbstractConnection<Mcp.Resources> newConnection = new McpConnection(responseObserver);
return new StreamObserver<Mcp.RequestResources>() {
private boolean initRequest = true;
@Override
public void onNext(Mcp.RequestResources requestResources) {
// init connection
if (initRequest) {
newConnection.setConnectionId(requestResources.getSinkNode().getId());
connections.put(newConnection.getConnectionId(), newConnection);
initRequest = false;
}
process(requestResources, newConnection);
}
@Override
public void onError(Throwable throwable) {
Loggers.MAIN.error("mcp: {} stream error.", newConnection.getConnectionId(), throwable);
clear();
}
@Override
public void onCompleted() {
responseObserver.onCompleted();
clear();
}
private void clear() {
connections.remove(newConnection.getConnectionId());
}
};
}
private void process(Mcp.RequestResources requestResources, AbstractConnection<Mcp.Resources> connection) {
if (!shouldPush(requestResources, connection)) {
return;
}
Mcp.Resources response = buildMcpResourcesResponse(requestResources.getCollection(), resourceManager.getResourceSnapshot());
connection.push(response, connection.getWatchedStatusByType(requestResources.getCollection()));
}
private boolean shouldPush(Mcp.RequestResources requestResources, AbstractConnection<Mcp.Resources> connection) {
String type = requestResources.getCollection();
String connectionId = connection.getConnectionId();
if (requestResources.getErrorDetail().getCode() != 0) {
Loggers.MAIN.error("mcp: ACK error, connection-id: {}, code: {}, message: {}",
connectionId,
requestResources.getErrorDetail().getCode(),
requestResources.getErrorDetail().getMessage());
return false;
}
WatchedStatus watchedStatus;
if (requestResources.getResponseNonce().isEmpty()) {
Loggers.MAIN.info("mcp: init request, type {}, connection-id {}, is incremental {}",
type, connectionId, requestResources.getIncremental());
watchedStatus = new WatchedStatus();
watchedStatus.setType(type);
connection.addWatchedResource(type, watchedStatus);
return true;
}
watchedStatus = connection.getWatchedStatusByType(type);
if (watchedStatus == null) {
Loggers.MAIN.info("mcp: reconnect, type {}, connection-id {}, is incremental {}",
type, connectionId, requestResources.getIncremental());
watchedStatus = new WatchedStatus();
watchedStatus.setType(type);
connection.addWatchedResource(type, watchedStatus);
return true;
}
if (!watchedStatus.getLatestNonce().equals(requestResources.getResponseNonce())) {
Loggers.MAIN.warn("mcp: request dis match, type {}, connection-id {}", type, connectionId);
return false;
}
// This request is ack, we should record nonce.
watchedStatus.setAckedNonce(requestResources.getResponseNonce());
Loggers.MAIN.info("mcp: ack, type {}, connection-id {}, nonce {}", type, connectionId,
requestResources.getResponseNonce());
return false;
}
public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) {
switch (event.getType()) {
case Service:
if (connections.size() == 0) {
return;
}
Loggers.MAIN.info("xds: event {} trigger push.", event.getType());
Mcp.Resources serviceEntryMcpResponse = buildMcpResourcesResponse(SERVICE_ENTRY_COLLECTION, resourceSnapshot);
for (AbstractConnection<Mcp.Resources> connection : connections.values()) {
WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_COLLECTION);
if (watchedStatus != null) {
connection.push(serviceEntryMcpResponse, watchedStatus);
}
}
break;
default:
Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType());
}
}
private Mcp.Resources buildMcpResourcesResponse(String type, ResourceSnapshot resourceSnapshot) {
@SuppressWarnings("unchecked")
ApiGenerator<Resource> serviceEntryGenerator = (ApiGenerator<Resource>) apiGeneratorFactory.getApiGenerator(type);
List<Resource> rawResources = serviceEntryGenerator.generate(resourceSnapshot);
String nonce = NonceGenerator.generateNonce();
return Mcp.Resources.newBuilder()
.setCollection(type)
.addAllResources(rawResources)
.setSystemVersionInfo(resourceSnapshot.getVersion())
.setNonce(nonce).build();
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.mcp;
import com.alibaba.nacos.istio.api.ApiGenerator;
import com.alibaba.nacos.istio.common.ResourceSnapshot;
import com.alibaba.nacos.istio.model.ServiceEntryWrapper;
import com.google.protobuf.Any;
import istio.mcp.v1alpha1.MetadataOuterClass;
import istio.mcp.v1alpha1.ResourceOuterClass.Resource;
import istio.networking.v1alpha3.ServiceEntryOuterClass;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.istio.api.ApiConstants.SERVICE_ENTRY_PROTO;
/**
* @author special.fy
*/
public class ServiceEntryMcpGenerator implements ApiGenerator<Resource> {
private volatile static ServiceEntryMcpGenerator singleton = null;
public static ServiceEntryMcpGenerator getInstance() {
if (singleton == null) {
synchronized (ServiceEntryMcpGenerator.class) {
if (singleton == null) {
singleton = new ServiceEntryMcpGenerator();
}
}
}
return singleton;
}
@Override
public List<Resource> generate(ResourceSnapshot resourceSnapshot) {
List<Resource> result = new ArrayList<>();
List<ServiceEntryWrapper> serviceEntries = resourceSnapshot.getServiceEntries();
for (ServiceEntryWrapper serviceEntryWrapper : serviceEntries) {
MetadataOuterClass.Metadata metadata = serviceEntryWrapper.getMetadata();
ServiceEntryOuterClass.ServiceEntry serviceEntry = serviceEntryWrapper.getServiceEntry();
Any any = Any.newBuilder().setValue(serviceEntry.toByteString()).setTypeUrl(SERVICE_ENTRY_PROTO).build();
result.add(Resource.newBuilder().setBody(any).setMetadata(metadata).build());
}
return result;
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.misc;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Stores some configurations for Istio integration.
*
* @author nkorange
* @since 1.1.4
*/
@Component
public class IstioConfig {
@Value("${nacos.istio.mcp.server.enabled:false}")
private boolean serverEnabled = false;
@Value("${nacos.istio.mcp.server.port:18848}")
private int serverPort = 18848;
@Value("${nacos.istio.mcp.push.interval:3000}")
private int mcpPushInterval;
@Value("${nacos.istio.domain.suffix:nacos}")
private String domainSuffix;
public boolean isServerEnabled() {
return serverEnabled;
}
public int getServerPort() {
return serverPort;
}
public String getDomainSuffix() {
return domainSuffix;
}
public int getMcpPushInterval() {
return mcpPushInterval;
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.misc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Loggers Holder.
*
* @author nkorange
* @since 1.1.4
*/
public class Loggers {
public static final Logger MAIN = LoggerFactory.getLogger("com.alibaba.nacos.istio.main");
}

View File

@ -0,0 +1,108 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.model;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author special.fy
*/
public class IstioService {
private String name;
private String groupName;
private String namespace;
private Long revision;
private List<Instance> hosts;
private Date createTimeStamp;
public IstioService(Service service, ServiceInfo serviceInfo) {
this.name = serviceInfo.getName();
this.groupName = serviceInfo.getGroupName();
this.namespace = service.getNamespace();
this.revision = service.getRevision();
// Record the create time of service to avoid trigger istio pull push.
// See https://github.com/istio/istio/pull/30684
createTimeStamp = new Date();
this.hosts = sanitizeServiceInfo(serviceInfo);
}
public IstioService(Service service, ServiceInfo serviceInfo, IstioService old) {
this.name = serviceInfo.getName();
this.groupName = serviceInfo.getGroupName();
this.namespace = service.getNamespace();
this.revision = service.getRevision();
// set the create time of service as old time to avoid trigger istio pull push.
// See https://github.com/istio/istio/pull/30684
createTimeStamp = old.getCreateTimeStamp();
this.hosts = sanitizeServiceInfo(serviceInfo);
}
private List<Instance> sanitizeServiceInfo(ServiceInfo serviceInfo) {
List<Instance> hosts = new ArrayList<>();
for (Instance instance : serviceInfo.getHosts()) {
if (instance.isHealthy() && instance.isEnabled()) {
hosts.add(instance);
}
}
// Panic mode, all instances are invalid, to push all instances to istio.
if (hosts.isEmpty()) {
hosts = serviceInfo.getHosts();
}
return hosts;
}
public String getName() {
return name;
}
public String getGroupName() {
return groupName;
}
public String getNamespace() {
return namespace;
}
public Long getRevision() {
return revision;
}
public List<Instance> getHosts() {
return hosts;
}
public Date getCreateTimeStamp() {
return createTimeStamp;
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.model;
import istio.mcp.v1alpha1.MetadataOuterClass.Metadata;
import istio.networking.v1alpha3.ServiceEntryOuterClass.ServiceEntry;
/**
* @author special.fy
*/
public class ServiceEntryWrapper {
private Metadata metadata;
private ServiceEntry serviceEntry;
public ServiceEntryWrapper(Metadata metadata, ServiceEntry serviceEntry) {
this.metadata = metadata;
this.serviceEntry = serviceEntry;
}
public Metadata getMetadata() {
return metadata;
}
public ServiceEntry getServiceEntry() {
return serviceEntry;
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.server;
import com.alibaba.nacos.istio.common.NacosResourceManager;
import com.alibaba.nacos.istio.mcp.NacosMcpService;
import com.alibaba.nacos.istio.misc.IstioConfig;
import com.alibaba.nacos.istio.misc.Loggers;
import com.alibaba.nacos.istio.xds.NacosXdsService;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.ServerInterceptors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.IOException;
/**
* @author special.fy
*/
@Service
public class IstioServer {
private Server server;
@Autowired
private IstioConfig istioConfig;
@Autowired
private ServerInterceptor serverInterceptor;
@Autowired
private NacosMcpService nacosMcpService;
@Autowired
private NacosXdsService nacosXdsService;
@Autowired
private NacosResourceManager nacosResourceManager;
/**
* Start.
*
* @throws IOException io exception
*/
@PostConstruct
public void start() throws IOException {
if (!istioConfig.isServerEnabled()) {
Loggers.MAIN.info("The Nacos Istio server is disabled.");
return;
}
nacosResourceManager.start();
Loggers.MAIN.info("Nacos Istio server, starting Nacos Istio server...");
server = ServerBuilder.forPort(istioConfig.getServerPort()).addService(ServerInterceptors.intercept(nacosMcpService, serverInterceptor))
.addService(ServerInterceptors.intercept(nacosXdsService, serverInterceptor)).build();
server.start();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Stopping Nacos Istio server...");
IstioServer.this.stop();
System.out.println("Nacos Istio server stopped...");
}
});
}
/**
* Stop.
*/
public void stop() {
if (server != null) {
server.shutdown();
}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.server;
import com.alibaba.nacos.istio.misc.Loggers;
import io.grpc.Grpc;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import org.springframework.stereotype.Component;
import java.net.SocketAddress;
/**
* @author special.fy
*/
@Component
public class ServerInterceptor implements io.grpc.ServerInterceptor {
@Override
public <R, T> ServerCall.Listener<R> interceptCall(ServerCall<R, T> call, Metadata headers,
ServerCallHandler<R, T> next) {
SocketAddress address = call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
String methodName = call.getMethodDescriptor().getFullMethodName();
Loggers.MAIN.info("remote address: {}, method: {}", address, methodName);
return next.startCall(call, headers);
}
}

View File

@ -0,0 +1,125 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.util;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.istio.model.IstioService;
import com.alibaba.nacos.istio.model.ServiceEntryWrapper;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.google.protobuf.Timestamp;
import istio.mcp.v1alpha1.MetadataOuterClass.Metadata;
import istio.networking.v1alpha3.GatewayOuterClass;
import istio.networking.v1alpha3.ServiceEntryOuterClass.ServiceEntry;
import istio.networking.v1alpha3.WorkloadEntryOuterClass.WorkloadEntry;
import org.apache.commons.lang.StringUtils;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* @author special.fy
*/
public class IstioCrdUtil {
public static final String VALID_DEFAULT_GROUP_NAME = "DEFAULT-GROUP";
private static final String ISTIO_HOSTNAME = "istio.hostname";
public static final String VALID_LABEL_KEY_FORMAT = "^([a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?)*/)?((?:[A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$";
public static final String VALID_LABEL_VALUE_FORMAT = "^((?:[A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$";
public static String buildServiceNameForServiceEntry(Service service) {
String group = !Constants.DEFAULT_GROUP.equals(service.getGroup()) ? service.getGroup() : VALID_DEFAULT_GROUP_NAME;
// DEFAULT_GROUP is invalid for istio,because the istio host only supports: [0-9],[A-Z],[a-z],-,*
return service.getName() + "." + group + "." + service.getNamespace();
}
public static ServiceEntryWrapper buildServiceEntry(String serviceName, String domainSuffix,IstioService istioService) {
if (istioService.getHosts().isEmpty()) {
return null;
}
ServiceEntry.Builder serviceEntryBuilder = ServiceEntry
.newBuilder().setResolution(ServiceEntry.Resolution.STATIC)
.setLocation(ServiceEntry.Location.MESH_INTERNAL);
int port = 0;
String protocol = "http";
String hostname = serviceName;
for (Instance instance : istioService.getHosts()) {
if (port == 0) {
port = instance.getPort();
}
if (StringUtils.isNotEmpty(instance.getMetadata().get("protocol"))) {
protocol = instance.getMetadata().get("protocol");
if ("triple".equals(protocol) || "tri".equals(protocol)){
protocol = "grpc";
}
}
String metaHostname = instance.getMetadata().get(ISTIO_HOSTNAME);
if (StringUtils.isNotEmpty(metaHostname)) {
hostname = metaHostname;
}
if (!instance.isHealthy() || !instance.isEnabled()) {
continue;
}
Map<String, String> metadata = new HashMap<>(1 << 3);
if (StringUtils.isNotEmpty(instance.getClusterName())) {
metadata.put("cluster", instance.getClusterName());
}
for (Map.Entry<String,String> entry : instance.getMetadata().entrySet()){
if (!Pattern.matches(VALID_LABEL_KEY_FORMAT, entry.getKey())){
continue;
}
if (!Pattern.matches(VALID_LABEL_VALUE_FORMAT, entry.getValue())){
continue;
}
metadata.put(entry.getKey(), entry.getValue());
}
WorkloadEntry workloadEntry = WorkloadEntry.newBuilder()
.setAddress(instance.getIp()).setWeight((int) instance.getWeight())
.putAllLabels(metadata).putPorts(protocol, instance.getPort()).build();
serviceEntryBuilder.addEndpoints(workloadEntry);
}
serviceEntryBuilder.addHosts(hostname + "." + domainSuffix).addPorts(
GatewayOuterClass.Port.newBuilder().setNumber(port).setName(protocol).setProtocol(protocol.toUpperCase()).build());
ServiceEntry serviceEntry = serviceEntryBuilder.build();
Date createTimestamp = istioService.getCreateTimeStamp();
Metadata metadata = Metadata.newBuilder()
.setName(istioService.getNamespace() + "/" + serviceName)
.putAnnotations("virtual", "1")
.putLabels("registryType", "nacos")
.setCreateTime(Timestamp.newBuilder().setSeconds(createTimestamp.getTime() / 1000).build())
.setVersion(String.valueOf(istioService.getRevision())).build();
return new ServiceEntryWrapper(metadata, serviceEntry);
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.util;
import com.alibaba.nacos.common.executor.ExecutorFactory;
import com.alibaba.nacos.common.executor.NameThreadFactory;
import com.alibaba.nacos.core.utils.ClassUtils;
import com.alibaba.nacos.istio.IstioApp;
import com.alibaba.nacos.sys.env.EnvUtil;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author special.fy
*/
public class IstioExecutor {
private static final ScheduledExecutorService NACOS_RESOURCE_WATCHER = ExecutorFactory.Managed
.newScheduledExecutorService(ClassUtils.getCanonicalName(IstioApp.class),
EnvUtil.getAvailableProcessors(2),
new NameThreadFactory("com.alibaba.nacos.istio.resource.watcher"));
private static final ExecutorService EVENT_HANDLE_EXECUTOR = ExecutorFactory.Managed
.newSingleExecutorService(ClassUtils.getCanonicalName(IstioApp.class),
new NameThreadFactory("com.alibaba.nacos.istio.event.handle"));
public static void registerNacosResourceWatcher(Runnable watcher, long initialDelay, long period) {
NACOS_RESOURCE_WATCHER.scheduleAtFixedRate(watcher, initialDelay, period, TimeUnit.MILLISECONDS);
}
public static <V> Future<V> asyncHandleEvent(Callable<V> task) {
return EVENT_HANDLE_EXECUTOR.submit(task);
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.util;
import com.alibaba.nacos.common.utils.UuidUtils;
/**
* @author special.fy
*/
public class NonceGenerator {
public static String generateNonce() {
return UuidUtils.generateUuid().replace("-", "");
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.xds;
import com.alibaba.nacos.istio.api.ApiGenerator;
import com.alibaba.nacos.istio.common.ResourceSnapshot;
import com.google.protobuf.Any;
import java.util.ArrayList;
import java.util.List;
/**
* @author special.fy
*/
public class EmptyXdsGenerator implements ApiGenerator<Any> {
private volatile static EmptyXdsGenerator singleton = null;
public static EmptyXdsGenerator getInstance() {
if (singleton == null) {
synchronized (EmptyXdsGenerator.class) {
if (singleton == null) {
singleton = new EmptyXdsGenerator();
}
}
}
return singleton;
}
@Override
public List<Any> generate(ResourceSnapshot resourceSnapshot) {
return new ArrayList<>();
}
}

View File

@ -0,0 +1,206 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.xds;
import com.alibaba.nacos.istio.api.ApiGenerator;
import com.alibaba.nacos.istio.api.ApiGeneratorFactory;
import com.alibaba.nacos.istio.common.*;
import com.alibaba.nacos.istio.misc.Loggers;
import com.alibaba.nacos.istio.util.NonceGenerator;
import com.google.protobuf.Any;
import io.envoyproxy.envoy.service.discovery.v3.AggregatedDiscoveryServiceGrpc;
import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest;
import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse;
import io.grpc.stub.StreamObserver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.alibaba.nacos.istio.api.ApiConstants.MESH_CONFIG_PROTO_PACKAGE;
import static com.alibaba.nacos.istio.api.ApiConstants.SERVICE_ENTRY_PROTO_PACKAGE;
/**
* @author special.fy
*/
@Service
public class NacosXdsService extends AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase {
private final Map<String, AbstractConnection<DiscoveryResponse>> connections = new ConcurrentHashMap<>(16);
public boolean hasClientConnection() {
return connections.size() != 0;
}
@Autowired
ApiGeneratorFactory apiGeneratorFactory;
@Autowired
NacosResourceManager resourceManager;
@Override
public StreamObserver<DiscoveryRequest> streamAggregatedResources(StreamObserver<DiscoveryResponse> responseObserver) {
// TODO add authN
// Init snapshot of nacos service info.
resourceManager.initResourceSnapshot();
AbstractConnection<DiscoveryResponse> newConnection = new XdsConnection(responseObserver);
return new StreamObserver<DiscoveryRequest>() {
private boolean initRequest = true;
@Override
public void onNext(DiscoveryRequest discoveryRequest) {
// init connection
if (initRequest) {
newConnection.setConnectionId(discoveryRequest.getNode().getId());
connections.put(newConnection.getConnectionId(), newConnection);
initRequest = false;
}
process(discoveryRequest, newConnection);
}
@Override
public void onError(Throwable throwable) {
Loggers.MAIN.error("xds: {} stream error.", newConnection.getConnectionId(), throwable);
clear();
}
@Override
public void onCompleted() {
Loggers.MAIN.info("xds: {} stream close.", newConnection.getConnectionId());
responseObserver.onCompleted();
clear();
}
private void clear() {
connections.remove(newConnection.getConnectionId());
}
};
}
public void process(DiscoveryRequest discoveryRequest, AbstractConnection<DiscoveryResponse> connection) {
if (!shouldPush(discoveryRequest, connection)) {
return;
}
DiscoveryResponse response = buildDiscoveryResponse(discoveryRequest.getTypeUrl(), resourceManager.getResourceSnapshot());
connection.push(response, connection.getWatchedStatusByType(discoveryRequest.getTypeUrl()));
}
private boolean shouldPush(DiscoveryRequest discoveryRequest, AbstractConnection<DiscoveryResponse> connection) {
String type = discoveryRequest.getTypeUrl();
String connectionId = connection.getConnectionId();
// Suitable for bug of istio
// See https://github.com/istio/istio/pull/34633
if (type.equals(MESH_CONFIG_PROTO_PACKAGE)) {
Loggers.MAIN.info("xds: type {} should be ignored.", type);
return false;
}
if (discoveryRequest.getErrorDetail().getCode() != 0) {
Loggers.MAIN.error("xds: ACK error, connection-id: {}, code: {}, message: {}",
connectionId,
discoveryRequest.getErrorDetail().getCode(),
discoveryRequest.getErrorDetail().getMessage());
return false;
}
WatchedStatus watchedStatus;
if (discoveryRequest.getResponseNonce().isEmpty()) {
Loggers.MAIN.info("xds: init request, type {}, connection-id {}, version {}",
type, connectionId, discoveryRequest.getVersionInfo());
watchedStatus = new WatchedStatus();
watchedStatus.setType(discoveryRequest.getTypeUrl());
connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus);
return true;
}
watchedStatus = connection.getWatchedStatusByType(discoveryRequest.getTypeUrl());
if (watchedStatus == null) {
Loggers.MAIN.info("xds: reconnect, type {}, connection-id {}, version {}, nonce {}.",
type, connectionId, discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce());
watchedStatus = new WatchedStatus();
watchedStatus.setType(discoveryRequest.getTypeUrl());
connection.addWatchedResource(discoveryRequest.getTypeUrl(), watchedStatus);
return true;
}
if (!watchedStatus.getLatestNonce().equals(discoveryRequest.getResponseNonce())) {
Loggers.MAIN.warn("xds: request dis match, type {}, connection-id {}",
discoveryRequest.getTypeUrl(),
connection.getConnectionId());
return false;
}
// This request is ack, we should record version and nonce.
watchedStatus.setAckedVersion(discoveryRequest.getVersionInfo());
watchedStatus.setAckedNonce(discoveryRequest.getResponseNonce());
Loggers.MAIN.info("xds: ack, type {}, connection-id {}, version {}, nonce {}", type, connectionId,
discoveryRequest.getVersionInfo(), discoveryRequest.getResponseNonce());
return false;
}
public void handleEvent(ResourceSnapshot resourceSnapshot, Event event) {
switch (event.getType()) {
case Service:
if (connections.size() == 0) {
return;
}
Loggers.MAIN.info("xds: event {} trigger push.", event.getType());
// Service Entry via MCP
DiscoveryResponse serviceEntryResponse = buildDiscoveryResponse(SERVICE_ENTRY_PROTO_PACKAGE, resourceSnapshot);
// TODO CDS, EDS
for (AbstractConnection<DiscoveryResponse> connection : connections.values()) {
// Service Entry via MCP
WatchedStatus watchedStatus = connection.getWatchedStatusByType(SERVICE_ENTRY_PROTO_PACKAGE);
if (watchedStatus != null) {
connection.push(serviceEntryResponse, watchedStatus);
}
// TODO CDS, EDS
}
break;
case Endpoint:
Loggers.MAIN.warn("Currently, endpoint event is not supported.");
break;
default:
Loggers.MAIN.warn("Invalid event {}, ignore it.", event.getType());
}
}
private DiscoveryResponse buildDiscoveryResponse(String type, ResourceSnapshot resourceSnapshot) {
@SuppressWarnings("unchecked")
ApiGenerator<Any> serviceEntryGenerator = (ApiGenerator<Any>) apiGeneratorFactory.getApiGenerator(type);
List<Any> rawResources = serviceEntryGenerator.generate(resourceSnapshot);
String nonce = NonceGenerator.generateNonce();
return DiscoveryResponse.newBuilder()
.setTypeUrl(type)
.addAllResources(rawResources)
.setVersionInfo(resourceSnapshot.getVersion())
.setNonce(nonce).build();
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.xds;
import com.alibaba.nacos.istio.api.ApiGenerator;
import com.alibaba.nacos.istio.common.ResourceSnapshot;
import com.alibaba.nacos.istio.model.ServiceEntryWrapper;
import com.google.protobuf.Any;
import istio.mcp.v1alpha1.MetadataOuterClass.Metadata;
import istio.mcp.v1alpha1.ResourceOuterClass.Resource;
import istio.networking.v1alpha3.ServiceEntryOuterClass.ServiceEntry;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.istio.api.ApiConstants.*;
/**
* @author special.fy
*/
public final class ServiceEntryXdsGenerator implements ApiGenerator<Any> {
private volatile static ServiceEntryXdsGenerator singleton = null;
public static ServiceEntryXdsGenerator getInstance() {
if (singleton == null) {
synchronized (ServiceEntryXdsGenerator.class) {
if (singleton == null) {
singleton = new ServiceEntryXdsGenerator();
}
}
}
return singleton;
}
@Override
public List<Any> generate(ResourceSnapshot resourceSnapshot) {
List<Resource> resources = new ArrayList<>();
List<ServiceEntryWrapper> serviceEntries = resourceSnapshot.getServiceEntries();
for (ServiceEntryWrapper serviceEntryWrapper : serviceEntries) {
Metadata metadata = serviceEntryWrapper.getMetadata();
ServiceEntry serviceEntry = serviceEntryWrapper.getServiceEntry();
Any any = Any.newBuilder().setValue(serviceEntry.toByteString()).setTypeUrl(SERVICE_ENTRY_PROTO).build();
resources.add(Resource.newBuilder().setBody(any).setMetadata(metadata).build());
}
List<Any> result = new ArrayList<>();
for (Resource resource : resources) {
result.add(Any.newBuilder().setValue(resource.toByteString()).setTypeUrl(MCP_RESOURCE_PROTO).build());
}
return result;
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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.
*/
package com.alibaba.nacos.istio.xds;
import com.alibaba.nacos.istio.common.AbstractConnection;
import com.alibaba.nacos.istio.common.WatchedStatus;
import com.alibaba.nacos.istio.misc.Loggers;
import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse;
import io.grpc.stub.StreamObserver;
/**
* @author special.fy
*/
public class XdsConnection extends AbstractConnection<DiscoveryResponse> {
public XdsConnection(StreamObserver<DiscoveryResponse> streamObserver) {
super(streamObserver);
}
@Override
public synchronized void push(DiscoveryResponse response, WatchedStatus watchedStatus) {
if (Loggers.MAIN.isDebugEnabled()) {
Loggers.MAIN.debug("discoveryResponse: {}", response.toString());
}
this.streamObserver.onNext(response);
// Update watched status
watchedStatus.setLatestVersion(response.getVersionInfo());
watchedStatus.setLatestNonce(response.getNonce());
Loggers.MAIN.info("xds: push, type: {}, connection-id {}, version {}, nonce {}, resource size {}.",
watchedStatus.getType(),
getConnectionId(),
response.getVersionInfo(),
response.getNonce(),
response.getResourcesCount());
}
}

View File

@ -0,0 +1,17 @@
#
# Copyright 1999-2023 Alibaba Group Holding Ltd.
#
# Licensed 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.
#
com.alibaba.nacos.istio.config.IstioEnabledFilter

View File

@ -0,0 +1,144 @@
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
package gogoproto;
import "google/protobuf/descriptor.proto";
option java_package = "com.google.protobuf";
option java_outer_classname = "GoGoProtos";
option go_package = "github.com/gogo/protobuf/gogoproto";
extend google.protobuf.EnumOptions {
optional bool goproto_enum_prefix = 62001;
optional bool goproto_enum_stringer = 62021;
optional bool enum_stringer = 62022;
optional string enum_customname = 62023;
optional bool enumdecl = 62024;
}
extend google.protobuf.EnumValueOptions {
optional string enumvalue_customname = 66001;
}
extend google.protobuf.FileOptions {
optional bool goproto_getters_all = 63001;
optional bool goproto_enum_prefix_all = 63002;
optional bool goproto_stringer_all = 63003;
optional bool verbose_equal_all = 63004;
optional bool face_all = 63005;
optional bool gostring_all = 63006;
optional bool populate_all = 63007;
optional bool stringer_all = 63008;
optional bool onlyone_all = 63009;
optional bool equal_all = 63013;
optional bool description_all = 63014;
optional bool testgen_all = 63015;
optional bool benchgen_all = 63016;
optional bool marshaler_all = 63017;
optional bool unmarshaler_all = 63018;
optional bool stable_marshaler_all = 63019;
optional bool sizer_all = 63020;
optional bool goproto_enum_stringer_all = 63021;
optional bool enum_stringer_all = 63022;
optional bool unsafe_marshaler_all = 63023;
optional bool unsafe_unmarshaler_all = 63024;
optional bool goproto_extensions_map_all = 63025;
optional bool goproto_unrecognized_all = 63026;
optional bool gogoproto_import = 63027;
optional bool protosizer_all = 63028;
optional bool compare_all = 63029;
optional bool typedecl_all = 63030;
optional bool enumdecl_all = 63031;
optional bool goproto_registration = 63032;
optional bool messagename_all = 63033;
optional bool goproto_sizecache_all = 63034;
optional bool goproto_unkeyed_all = 63035;
}
extend google.protobuf.MessageOptions {
optional bool goproto_getters = 64001;
optional bool goproto_stringer = 64003;
optional bool verbose_equal = 64004;
optional bool face = 64005;
optional bool gostring = 64006;
optional bool populate = 64007;
optional bool stringer = 67008;
optional bool onlyone = 64009;
optional bool equal = 64013;
optional bool description = 64014;
optional bool testgen = 64015;
optional bool benchgen = 64016;
optional bool marshaler = 64017;
optional bool unmarshaler = 64018;
optional bool stable_marshaler = 64019;
optional bool sizer = 64020;
optional bool unsafe_marshaler = 64023;
optional bool unsafe_unmarshaler = 64024;
optional bool goproto_extensions_map = 64025;
optional bool goproto_unrecognized = 64026;
optional bool protosizer = 64028;
optional bool compare = 64029;
optional bool typedecl = 64030;
optional bool messagename = 64033;
optional bool goproto_sizecache = 64034;
optional bool goproto_unkeyed = 64035;
}
extend google.protobuf.FieldOptions {
optional bool nullable = 65001;
optional bool embed = 65002;
optional string customtype = 65003;
optional string customname = 65004;
optional string jsontag = 65005;
optional string moretags = 65006;
optional string casttype = 65007;
optional string castkey = 65008;
optional string castvalue = 65009;
optional bool stdtime = 65010;
optional bool stdduration = 65011;
optional bool wktpointer = 65012;
}

View File

@ -0,0 +1,155 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/any";
option java_package = "com.google.protobuf";
option java_outer_classname = "AnyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// `Any` contains an arbitrary serialized protocol buffer message along with a
// URL that describes the type of the serialized message.
//
// Protobuf library provides support to pack/unpack Any values in the form
// of utility functions or additional generated methods of the Any type.
//
// Example 1: Pack and unpack a message in C++.
//
// Foo foo = ...;
// Any any;
// any.PackFrom(foo);
// ...
// if (any.UnpackTo(&foo)) {
// ...
// }
//
// Example 2: Pack and unpack a message in Java.
//
// Foo foo = ...;
// Any any = Any.pack(foo);
// ...
// if (any.is(Foo.class)) {
// foo = any.unpack(Foo.class);
// }
//
// Example 3: Pack and unpack a message in Python.
//
// foo = Foo(...)
// any = Any()
// any.Pack(foo)
// ...
// if any.Is(Foo.DESCRIPTOR):
// any.Unpack(foo)
// ...
//
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := ptypes.MarshalAny(foo)
// ...
// foo := &pb.Foo{}
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/'
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
// name "y.z".
//
//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
// representation of the deserialized, embedded message, with an
// additional field `@type` which contains the type URL. Example:
//
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
//
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
// `value` which holds the custom JSON in addition to the `@type`
// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
//
message Any {
// A URL/resource name that uniquely identifies the type of the serialized
// protocol buffer message. This string must contain at least
// one "/" character. The last segment of the URL's path must represent
// the fully qualified name of the type (as in
// `path/google.protobuf.Duration`). The name should be in a canonical form
// (e.g., leading "." is not accepted).
//
// In practice, teams usually precompile into the binary all types that they
// expect it to use in the context of Any. However, for URLs which use the
// scheme `http`, `https`, or no scheme, one can optionally set up a type
// server that maps type URLs to message definitions as follows:
//
// * If no scheme is provided, `https` is assumed.
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Note: this functionality is not currently available in the official
// protobuf release, and it is not used for type URLs beginning with
// type.googleapis.com.
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
string type_url = 1;
// Must be a valid serialized protocol buffer of the above specified type.
bytes value = 2;
}

View File

@ -0,0 +1,165 @@
// Copyright 2018 Istio Authors
//
// Licensed 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.
# Mesh Configuration Protocol (MCP)
## Introduction
This folder contains the proto buffers for the Mesh Configuration
Protocol (MCP). MCP is based on
[XDS](https://github.com/envoyproxy/data-plane-api/blob/master/xds_protocol.rst#streaming-grpc-subscriptions)
and maintains conceptual alignment with it, despite the specific
service and proto definitions being different.
## Overview
MCP is a subscription-based configuration distribution API. The
configuration consumer (i.e. sink) requests updates for collections of
resources from a configuration producer (i.e. source). The source
pushes resource updates to the sink when resources are added, updated,
or deleted. The sink positively ACK's the resource update, if it was
accepted, and NACK's if it was rejected, e.g. because a resource was
invalid. The source may push additional update once the previous
update was ACK/NACK'd. The source should only have one outstanding
update (per-collection) in flight at a time.
MCP is a pair of bidirectional streaming gRPC API services
(`ResourceSource` and `ResourceSink`).
* The `ResourceSource` service is used when the resource source is the
server and the sink is a client. By default, Galley implements the
`ResourceSource` service and Pilot/Mixer connect as clients.
* The `ResourceSink` service is used when the resource source is a
client and the sink is the server. Galley can be configured to
optionally "dial-out" to a remote configuration sink, e.g. Pilot is in
another cluster where it cannot, as a client, initiate
connection to Galley. In this scenario, Pilot would implement the
`ResourceSink` service and Galley would connect as a client.
ResourceSource and ResourceSink are semantically equivalent with
regards to the message exchange. The only meaningful difference is who
initiates the connection and opens the grpc stream.
## Data model
MCP is the mechanism of transport whereby Pilot and Mixer can be
configured by a manager component. MCP defines a common per-resource
metadata format and resource specific contents is defined elsewhere
(e.g. <https://github.com/istio/api/tree/master/networking/v1alpha3>).
### Collections
Resources of the same type are organized into named
collections. Istio API collection names are of the form
`istio/<area>/<version>/<api>` where `<area>`, `<version>`, and `<api>`
are defined by the [API style guidelines](../GUIDELINES.md). For
example, the collection name for VirtualService is
`istio/networking/v1alpha3/virtualservices`.
### Metadata
## Connection establishment
* `ResourceSource` service - The client is the resource sink. The
client dials the server and establishes a new gRPC stream. The client
sends RequestResources and receive Resources messages.
![ResourceSource connection setup](v1alpha1/diagrams/ResourceSource-connection-setup.svg)
* `ResourceSink` service - The client is the resource source. The
client dials the server and establishes a new gRPC stream. The server
sends RequestResources and receive Resources messages.
![ResourceSink connection setup](v1alpha1/diagrams/ResourceSink-connection-setup.svg)
## Configuration updates
The following overview applies to both ResourceSink and ResourceSource
services, regardless of client/server roles.
The resource update protocol is derived from Incremental xDS. The
protocol exchange is mostly the same except that resource hints have
been removed. Most of the text and diagrams below are copied from the
Incremental xDS docs and adjusted accordingly.
In MCP, resources are first organized by collection. Within each
collection, resources are uniquely identifiable by their metadata
name. Individual resources are versioned to differentiate newer
versions of the same named resource.
A `RequestResource` message can be sent in two situations:
* Initial message in an MCP bidirectional change stream
* As an ACK or NACK response to a previous `Resources` message. In
this case the `response_nonce` is set to the nonce value from the
`Resources` message. ACK/NACK is determined by the presence of
`error_detail` in the subsequent request.
The initial `RequestResources` messages includes the collection
corresponding to the subscribed set of resources
(e.g. VirtualService), the node sink identifier, and nonce fields, and
initial_resource_version (more on that later). The source send a
`Resources` message when the requested resources are available. After
processing the `Resources` message , the sink sends a new
`RequestResources` message on the stream, specifying the last version
successfully applied and the nonce provided by the source.
The nonce field is used to pair `RequestResources` and `Resources`
messages per collection. The source should only send one outstanding
`Resource` message at a time (per-collection) and wait for the sink to
ACK/NACK. Upon receiving an update, the sink is expected to send an
ACK/NACK relatively quickly after decoding, validating, and persisting
the update to its internal configuration store.
The source should ignore requests with stale and unknown nonces that
do not match the nonce in the most recently sent `Resource` message.
### Success examples
The following example shows the sink receiving a sequence of changes
which are successfully ACK'd.
![Resource full-state update success](v1alpha1/diagrams/collection-full-state-update-success.svg)
The following example shows the same desired resource delivered with
incremental updates. This example assumes incremental is supported by
the source. When source does not support incremental updates, the
pushed `Resources` will always have incremental set to false,
regardles of whether the sink requested an incremental update. At any
time, the source can decide to push a full-state update, ignoring the
sink's request. Both sides must negotiate (i.e. agree) to use
incremental on a per request/response basis for an update to be sent
incrementally.
![Resource full-state incremental success](v1alpha1/diagrams/collection-incremental-update-success.svg)
### Error example
The following example shows what happens when a change cannot be applied.
![Resource update error](v1alpha1/diagrams/collection-update-error.svg)
The sink should only NACK in _exceptional_ cases. For example, if a set of
resources was invalid, malformed, or could not be decoded. NACK'd updates
should raise an alarm for subsequent investigation by a human. The source
should not resend the same set of resources that were previously NACK'd.
Canary pushes to dedicated sinks may also be used to verify correctness
(non-NACK) before pushing to a larger fleet of resource sinks.
The nonce in MCP is used to match RequestResources and Resources. On
reconnect, the sinks may attempt to resume a session with the same
source by specifying the known resources version with
initial_resource_version for each collection.

View File

@ -0,0 +1,309 @@
// Copyright 2018 Istio Authors
//
// Licensed 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.
syntax = "proto3";
package istio.mcp.v1alpha1;
import "google/rpc/status.proto";
import "gogoproto/gogo.proto";
import "mcp/v1alpha1/resource.proto";
option go_package="istio.io/api/mcp/v1alpha1";
option (gogoproto.equal_all) = true;
// Identifies a specific MCP sink node instance. The node identifier is
// presented to the resource source, which may use this identifier
// to distinguish per sink configuration for serving. This
// information is not authoritative. Authoritative identity should come
// from the underlying transport layer (e.g. rpc credentials).
message SinkNode {
// An opaque identifier for the MCP node.
string id = 1;
// Opaque annotations extending the node identifier.
map<string,string> annotations = 2;
}
// A MeshConfigRequest requests a set of versioned resources of the
// same type for a given client.
message MeshConfigRequest {
// The version_info provided in the request messages will be the
// version_info received with the most recent successfully processed
// response or empty on the first request. It is expected that no
// new request is sent after a response is received until the client
// instance is ready to ACK/NACK the new configuration. ACK/NACK
// takes place by returning the new API config version as applied or
// the previous API config version respectively. Each type_url (see
// below) has an independent version associated with it.
string version_info = 1;
// The sink node making the request.
SinkNode sink_node = 2;
// Type of the resource that is being requested, e.g.
// "type.googleapis.com/istio.io.networking.v1alpha3.VirtualService".
string type_url = 3;
// The nonce corresponding to MeshConfigResponse being
// ACK/NACKed. See above discussion on version_info and the
// MeshConfigResponse nonce comment. This may be empty if no nonce is
// available, e.g. at startup.
string response_nonce = 4;
// This is populated when the previous MeshConfigResponse failed to
// update configuration. The *message* field in *error_details*
// provides the client internal exception related to the failure. It
// is only intended for consumption during manual debugging, the
// string provided is not guaranteed to be stable across client
// versions.
google.rpc.Status error_detail = 5;
}
// A MeshConfigResponse delivers a set of versioned resources of the
// same type in response to a MeshConfigRequest.
message MeshConfigResponse {
// The version of the response data.
string version_info = 1;
// The response resources wrapped in the common MCP *Resource*
// message.
repeated Resource resources = 2 [(gogoproto.nullable) = false];
// Type URL for resources wrapped in the provided resources(s). This
// must be consistent with the type_url in the wrapper messages if
// resources is non-empty.
string type_url = 3;
// The nonce provides a way to explicitly ack a specific
// MeshConfigResponse in a following MeshConfigRequest. Additional
// messages may have been sent by client to the management server for
// the previous version on the stream prior to this
// MeshConfigResponse, that were unprocessed at response send
// time. The nonce allows the management server to ignore any
// further MeshConfigRequests for the previous version until a
// MeshConfigRequest bearing the nonce.
string nonce = 4;
}
// IncrementalMeshConfigRequest are be sent in 2 situations:
//
// 1. Initial message in a MCP bidirectional gRPC stream.
//
// 2. As a ACK or NACK response to a previous IncrementalMeshConfigResponse.
// In this case the response_nonce is set to the nonce value in the Response.
// ACK or NACK is determined by the absence or presence of error_detail.
message IncrementalMeshConfigRequest {
// The sink node making the request.
SinkNode sink_node = 1;
// Type of the resource that is being requested, e.g.
// "type.googleapis.com/istio.io.networking.v1alpha3.VirtualService".
string type_url = 2;
// When the IncrementalMeshConfigRequest is the first in a stream,
// the initial_resource_versions must be populated. Otherwise,
// initial_resource_versions must be omitted. The keys are the
// resources names of the MCP resources known to the MCP client. The
// values in the map are the associated resource level version info.
map<string, string> initial_resource_versions = 3;
// When the IncrementalMeshConfigRequest is a ACK or NACK message in response
// to a previous IncrementalMeshConfigResponse, the response_nonce must be the
// nonce in the IncrementalMeshConfigResponse.
// Otherwise response_nonce must be omitted.
string response_nonce = 4;
// This is populated when the previous IncrementalMeshConfigResponses
// failed to update configuration. The *message* field in *error_details*
// provides the client internal exception related to the failure.
google.rpc.Status error_detail = 5;
}
// IncrementalMeshConfigResponses do not need to include a full
// snapshot of the tracked resources. Instead they are a diff to the
// state of a MCP client. Per resource versions allow servers and
// clients to track state at the resource granularity. An MCP
// incremental session is always in the context of a gRPC
// bidirectional stream. This allows the MCP server to keep track of
// the state of MCP clients connected to it.
//
// In Incremental MCP the nonce field is required and used to pair
// IncrementalMeshConfigResponse to an IncrementalMeshConfigRequest
// ACK or NACK. Optionally, a response message level
// system_version_info is present for debugging purposes only.
message IncrementalMeshConfigResponse {
// The version of the response data (used for debugging).
string system_version_info = 1;
// The response resources wrapped in the common MCP *Resource*
// message. These are typed resources that match the type url in the
// IncrementalMeshConfigRequest.
repeated Resource resources = 2 [(gogoproto.nullable) = false];
// Resources names of resources that have be deleted and to be
// removed from the MCP Client. Removed resources for missing
// resources can be ignored.
repeated string removed_resources = 3;
// The nonce provides a way for IncrementalMeshConfigRequests to
// uniquely reference an IncrementalMeshConfigResponse. The nonce is
// required.
string nonce = 4;
}
// The aggregated mesh configuration services allow a single
// management server, via a single gRPC stream, to deliver all API
// updates.
service AggregatedMeshConfigService {
// StreamAggregatedResources provides the ability to carefully
// sequence updates across multiple resource types. A single stream
// is used with multiple independent MeshConfigRequest /
// MeshConfigResponses sequences multiplexed via the type URL.
rpc StreamAggregatedResources(stream MeshConfigRequest)
returns (stream MeshConfigResponse) {
}
// IncrementalAggregatedResources provides the ability to incrementally
// update the resources on the client. This supports the goal of
// scalability of MCP resources.
rpc IncrementalAggregatedResources(stream IncrementalMeshConfigRequest)
returns (stream IncrementalMeshConfigResponse) {
}
}
// A RequestResource can be sent in two situations:
//
// Initial message in an MCP bidirectional change stream
// as an ACK or NACK response to a previous Resources. In
// this case the response_nonce is set to the nonce value
// in the Resources. ACK/NACK is determined by the presence
// of error_detail.
//
// * ACK (nonce!="",error_details==nil)
// * NACK (nonce!="",error_details!=nil)
// * New/Update request (nonce=="",error_details ignored)
//
message RequestResources {
// The sink node making the request.
SinkNode sink_node = 1;
// Type of resource collection that is being requested, e.g.
//
// istio/networking/v1alpha3/VirtualService
// k8s/<apiVersion>/<kind>
string collection = 2;
// When the RequestResources is the first in a stream, the initial_resource_versions must
// be populated. Otherwise, initial_resource_versions must be omitted. The keys are the
// resources names of the MCP resources known to the MCP client. The values in the map
// are the associated resource level version info.
map<string, string> initial_resource_versions = 3;
// When the RequestResources is an ACK or NACK message in response to a previous RequestResources,
// the response_nonce must be the nonce in the RequestResources. Otherwise response_nonce must
// be omitted.
string response_nonce = 4;
// This is populated when the previously received resources could not be applied
// The *message* field in *error_details* provides the source internal error
// related to the failure.
google.rpc.Status error_detail = 5;
// Request an incremental update for the specified collection. The source may choose to
// honor this request or ignore and and provide a full-state update in the corresponding
// `Resource` response.
bool incremental = 6;
}
// Resources do not need to include a full snapshot of the tracked
// resources. Instead they are a diff to the state of a MCP client.
// Per resource versions allow sources and sinks to track state at
// the resource granularity. An MCP incremental session is always
// in the context of a gRPC bidirectional stream. This allows the
// MCP source to keep track of the state of MCP sink connected to
// it.
//
// In Incremental MCP the nonce field is required and used to pair
// Resources to an RequestResources ACK or NACK.
message Resources {
// The version of the response data (used for debugging).
string system_version_info = 1;
// Type of resource collection that is being requested, e.g.
//
// istio/networking/v1alpha3/VirtualService
// k8s/<apiVersion>/<kind>
string collection = 2;
// The response resources wrapped in the common MCP *Resource* message.
// These are typed resources that match the type url in the
// RequestResources message.
//
// When `incremental` is true, this contains an array of resources to add/update
// for the specified collection. This modifies the existing collection at the sink
//
// When `incremental` is false, this contains the full set of resources for the
// specified collection. This replaces any previously delivered resources.
repeated Resource resources = 3 [(gogoproto.nullable) = false];
// Names of resources that have been deleted and to be
// removed from the MCP sink node. Removed resources for missing
// resources can be ignored.
//
// When `incremental` is true, this contains an array of resource names to remove
// for the specified collection. This modifies the existing resource collection at
// the sink.
//
// When `incremental` is false, this field should be ignored.
repeated string removed_resources = 4;
// Required. The nonce provides a way for RequestChange to uniquely
// reference a RequestResources.
string nonce = 5;
// This resource response is an incremental update. The source should only send
// incremental updates if the sink requested them.
bool incremental = 6;
}
// ResourceSource and ResourceSink services are semantically
// equivalent with regards to the message exchange. The only meaningful
// difference is who initiates the connection and opens the stream. The
// following high-level overview applies to both service variants.
//
// After the connection and streams have been established, the sink sends
// a RequestResource messages to request the initial set of resources. The
// source sends a Resource message when new resources are available for the
// requested type. In response, the sink sends another RequestResource
// to ACK/NACK the received resources and request the next set of resources.
// Service where the sink is the gRPC client. The sink is responsible for
// initiating connections and opening streams.
service ResourceSource {
// The sink, acting as gRPC client, establishes a new resource stream
// with the source. The sink sends RequestResources message to
// and receives Resources messages from the source.
rpc EstablishResourceStream(stream RequestResources) returns (stream Resources) {}
}
// Service where the source is the gRPC client. The source is responsible for
// initiating connections and opening streams.
service ResourceSink {
// The source, acting as gRPC client, establishes a new resource stream
// with the sink. The sink sends RequestResources message to and
// receives Resources messages from the source.
rpc EstablishResourceStream(stream Resources) returns (stream RequestResources) {}
}

View File

@ -0,0 +1,75 @@
// Copyright 2018 Istio Authors
//
// Licensed 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.
syntax = "proto3";
package istio.mcp.v1alpha1;
import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";
option go_package="istio.io/api/mcp/v1alpha1";
option (gogoproto.equal_all) = true;
// Metadata information that all resources within the Mesh Configuration Protocol must have.
message Metadata {
// Fully qualified name of the resource. Unique in context of a collection.
//
// The fully qualified name consists of a directory and basename. The directory identifies
// the resources location in a resource hierarchy. The basename identifies the specific
// resource name within the context of that directory.
//
// The directory and basename are composed of one or more segments. Segments must be
// valid [DNS labels](https://tools.ietf.org/html/rfc1123). "/" is the delimiter between
// segments
//
// The rightmost segment is the basename. All segments to the
// left of the basename form the directory. Segments moving towards the left
// represent higher positions in the resource hierarchy, similar to reverse
// DNS notation. e.g.
//
// /<org>/<team>/<subteam>/<resource basename>
//
// An empty directory indicates a resource that is located at the root of the
// hierarchy, e.g.
//
// /<globally scoped resource>
//
// On Kubernetes the resource hierarchy is two-levels: namespaces and
// cluster-scoped (i.e. global).
//
// Namespace resources fully qualified name is of the form:
//
// "<k8s namespace>/<k8s resource name>"
//
// Cluster scoped resources are located at the root of the hierarchy and are of the form:
//
// "/<k8s resource name>"
string name = 1;
// The creation timestamp of the resource.
google.protobuf.Timestamp create_time = 2;
// Resource version. This is used to determine when resources change across
// resource updates. It should be treated as opaque by consumers/sinks.
string version = 3;
// Map of string keys and values that can be used to organize and categorize
// resources within a collection.
map<string,string> labels = 4;
// Map of string keys and values that can be used by source and sink to communicate
// arbitrary metadata about this resource.
map<string,string> annotations = 5;
}

View File

@ -0,0 +1,35 @@
// Copyright 2018 Istio Authors
//
// Licensed 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.
syntax = "proto3";
// This package defines the common, core types used by the Mesh Configuration Protocol.
package istio.mcp.v1alpha1;
import "google/protobuf/any.proto";
import "gogoproto/gogo.proto";
import "mcp/v1alpha1/metadata.proto";
option go_package="istio.io/api/mcp/v1alpha1";
option (gogoproto.equal_all) = true;
// Resource as transferred via the Mesh Configuration Protocol. Each
// resource is made up of common metadata, and a type-specific resource payload.
message Resource {
// Common metadata describing the resource.
istio.mcp.v1alpha1.Metadata metadata = 1;
// The primary payload for the resource.
google.protobuf.Any body = 2;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,803 @@
// Copyright Istio Authors
//
// Licensed 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.
syntax = "proto3";
import "google/api/field_behavior.proto";
import "google/protobuf/struct.proto";
import "networking/v1alpha3/sidecar.proto";
// $schema: istio.networking.v1alpha3.EnvoyFilter
// $title: Envoy Filter
// $description: Customizing Envoy configuration generated by Istio.
// $location: https://istio.io/docs/reference/config/networking/envoy-filter.html
// $aliases: [/docs/reference/config/networking/v1alpha3/envoy-filter]
// `EnvoyFilter` provides a mechanism to customize the Envoy
// configuration generated by Istio Pilot. Use EnvoyFilter to modify
// values for certain fields, add specific filters, or even add
// entirely new listeners, clusters, etc. This feature must be used
// with care, as incorrect configurations could potentially
// destabilize the entire mesh. Unlike other Istio networking objects,
// EnvoyFilters are additively applied. Any number of EnvoyFilters can
// exist for a given workload in a specific namespace. The order of
// application of these EnvoyFilters is as follows: all EnvoyFilters
// in the config [root
// namespace](https://istio.io/docs/reference/config/istio.mesh.v1alpha1/#MeshConfig),
// followed by all matching EnvoyFilters in the workload's namespace.
//
// **NOTE 1**: Some aspects of this API is deeply tied to the internal
// implementation in Istio networking subsystem as well as Envoy's XDS
// API. While the EnvoyFilter API by itself will maintain backward
// compatibility, any envoy configuration provided through this
// mechanism should be carefully monitored across Istio proxy version
// upgrades, to ensure that deprecated fields are removed and replaced
// appropriately.
//
// **NOTE 2**: When multiple EnvoyFilters are bound to the same
// workload in a given namespace, all patches will be processed
// sequentially in order of creation time. The behavior is undefined
// if multiple EnvoyFilter configurations conflict with each other.
//
// **NOTE 3**: To apply an EnvoyFilter resource to all workloads
// (sidecars and gateways) in the system, define the resource in the
// config [root
// namespace](https://istio.io/docs/reference/config/istio.mesh.v1alpha1/#MeshConfig),
// without a workloadSelector.
//
// The example below declares a global default EnvoyFilter resource in
// the root namespace called `istio-config`, that adds a custom
// protocol filter on all sidecars in the system, for outbound port
// 9307. The filter should be added before the terminating tcp_proxy
// filter to take effect. In addition, it sets a 30s idle timeout for
// all HTTP connections in both gateways and sidecars.
//
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: EnvoyFilter
// metadata:
// name: custom-protocol
// namespace: istio-config # as defined in meshConfig resource.
// spec:
// configPatches:
// - applyTo: NETWORK_FILTER
// match:
// context: SIDECAR_OUTBOUND # will match outbound listeners in all sidecars
// listener:
// portNumber: 9307
// filterChain:
// filter:
// name: "envoy.filters.network.tcp_proxy"
// patch:
// operation: INSERT_BEFORE
// value:
// # This is the full filter config including the name and config or typed_config section.
// name: "envoy.config.filter.network.custom_protocol"
// config:
// ...
// - applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
// match:
// # context omitted so that this applies to both sidecars and gateways
// listener:
// filterChain:
// filter:
// name: "envoy.filters.network.http_connection_manager"
// patch:
// operation: MERGE
// value:
// name: "envoy.filters.network.http_connection_manager"
// typed_config:
// "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
// common_http_protocol_options:
// idle_timeout: 30s
//```
//
// The following example enables Envoy's Lua filter for all inbound
// HTTP calls arriving at service port 8080 of the reviews service pod
// with labels "app: reviews", in the bookinfo namespace. The lua
// filter calls out to an external service internal.org.net:8888 that
// requires a special cluster definition in envoy. The cluster is also
// added to the sidecar as part of this configuration.
//
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: EnvoyFilter
// metadata:
// name: reviews-lua
// namespace: bookinfo
// spec:
// workloadSelector:
// labels:
// app: reviews
// configPatches:
// # The first patch adds the lua filter to the listener/http connection manager
// - applyTo: HTTP_FILTER
// match:
// context: SIDECAR_INBOUND
// listener:
// portNumber: 8080
// patch:
// operation: ADD
// filterClass: AUTHZ # This filter will run *after* the Istio authz filter.
// value: # lua filter specification
// name: envoy.filters.http.lua
// typed_config:
// "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
// inlineCode: |
// function envoy_on_request(request_handle)
// -- Make an HTTP call to an upstream host with the following headers, body, and timeout.
// local headers, body = request_handle:httpCall(
// "lua_cluster",
// {
// [":method"] = "POST",
// [":path"] = "/acl",
// [":authority"] = "internal.org.net"
// },
// "authorize call",
// 5000)
// end
// # The second patch adds the cluster that is referenced by the lua code
// # cds match is omitted as a new cluster is being added
// - applyTo: CLUSTER
// match:
// context: SIDECAR_OUTBOUND
// patch:
// operation: ADD
// value: # cluster specification
// name: "lua_cluster"
// type: STRICT_DNS
// connect_timeout: 0.5s
// lb_policy: ROUND_ROBIN
// hosts:
// - socket_address:
// protocol: TCP
// address: "internal.org.net"
// port_value: 8888
//
// ```
//
// The following example overwrites certain fields (HTTP idle timeout
// and X-Forward-For trusted hops) in the HTTP connection manager in a
// listener on the ingress gateway in istio-system namespace for the
// SNI host app.example.com:
//
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: EnvoyFilter
// metadata:
// name: hcm-tweaks
// namespace: istio-system
// spec:
// workloadSelector:
// labels:
// istio: ingressgateway
// configPatches:
// - applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
// match:
// context: GATEWAY
// listener:
// filterChain:
// sni: app.example.com
// filter:
// name: "envoy.filters.network.http_connection_manager"
// patch:
// operation: MERGE
// value:
// common_http_protocol_options:
// idle_timeout: 30s
// xff_num_trusted_hops: 5
//```
//
// The following example inserts an attributegen filter
// that produces `istio_operationId` attribute which is consumed
// by the istio.stats fiter. `filterClass: STATS` encodes this dependency.
//
//
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: EnvoyFilter
// metadata:
// name: reviews-request-operation
// namespace: myns
// spec:
// workloadSelector:
// labels:
// app: reviews
// configPatches:
// - applyTo: HTTP_FILTER
// match:
// context: SIDECAR_INBOUND
// patch:
// operation: ADD
// filterClass: STATS # This filter will run *before* the Istio stats filter.
// value:
// name: istio.request_operation
// typed_config:
// "@type": type.googleapis.com/udpa.type.v1.TypedStruct
// type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
// value:
// config:
// configuration: |
// {
// "attributes": [
// {
// "output_attribute": "istio_operationId",
// "match": [
// {
// "value": "ListReviews",
// "condition": "request.url_path == '/reviews' && request.method == 'GET'"
// }]
// }]
// }
// vm_config:
// runtime: envoy.wasm.runtime.null
// code:
// local: { inline_string: "envoy.wasm.attributegen" }
// ```
//
// The following example inserts an http ext_authz filter in the `myns` namespace.
//
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: EnvoyFilter
// metadata:
// name: myns-ext-authz
// namespace: myns
// spec:
// configPatches:
// - applyTo: HTTP_FILTER
// match:
// context: SIDECAR_INBOUND
// patch:
// operation: ADD
// filterClass: AUTHZ # This filter will run *after* the Istio authz filter.
// value:
// name: envoy.filters.http.ext_authz
// typed_config:
// "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
// grpc_service:
// envoy_grpc:
// cluster_name: acme-ext-authz
// initial_metadata:
// - key: foo
// value: myauth.acme # required by local ext auth server.
// ```
//
// A workload in the `myns` namespace needs to access a different ext_auth server
// that does not accept initial metadata. Since proto merge cannot remove fields, the
// following configuration uses the `REPLACE` operation. If you do not need to inherit
// fields, REPLACE is preferred over MERGE.
//
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: EnvoyFilter
// metadata:
// name: mysvc-ext-authz
// namespace: myns
// spec:
// workloadSelector:
// labels:
// app: mysvc
// configPatches:
// - applyTo: HTTP_FILTER
// match:
// context: SIDECAR_INBOUND
// patch:
// operation: REPLACE
// value:
// name: envoy.filters.http.ext_authz
// typed_config:
// "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
// grpc_service:
// envoy_grpc:
// cluster_name: acme-ext-authz-alt
// ```
//
// The following example deploys a Wasm extension for all inbound sidecar HTTP requests.
//
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: EnvoyFilter
// metadata:
// name: wasm-example
// namespace: myns
// spec:
// configPatches:
// # The first patch defines a named Wasm extension and provides a URL to fetch Wasm binary from,
// # and the binary configuration. It should come before the next patch that applies it.
// # This resource is visible to all proxies in the namespace "myns". It is possible to provide
// # multiple definitions for the same name "my-wasm-extension" in multiple namespaces. We recommend that:
// # - if overriding is desired, then the root level definition can be overriden per namespace with REPLACE.
// # - if overriding is not desired, then the name should be qualified with the namespace "myns/my-wasm-extension",
// # to avoid accidental name collisions.
// - applyTo: EXTENSION_CONFIG
// patch:
// operation: ADD # REPLACE is also supported, and would override a cluster level resource with the same name.
// value:
// name: my-wasm-extension
// typed_config:
// "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
// config:
// root_id: my-wasm-root-id
// vm_config:
// vm_id: my-wasm-vm-id
// runtime: envoy.wasm.runtime.v8
// code:
// remote:
// http_uri:
// uri: http://my-wasm-binary-uri
// configuration: |
// {}
// # The second patch instructs to apply the above Wasm filter to the listener/http connection manager.
// - applyTo: HTTP_FILTER
// match:
// context: SIDECAR_INBOUND
// patch:
// operation: ADD
// filterClass: AUTHZ # This filter will run *after* the Istio authz filter.
// value:
// name: my-wasm-extension # This must match the name above
// config_discovery:
// config_source:
// api_config_source:
// api_type: GRPC
// transport_api_version: V3
// grpc_services:
// - envoy_grpc:
// cluster_name: xds-grpc
// type_urls: ["envoy.extensions.filters.http.wasm.v3.Wasm"]
// ```
package istio.networking.v1alpha3;
option go_package = "istio.io/api/networking/v1alpha3";
// EnvoyFilter provides a mechanism to customize the Envoy configuration
// generated by Istio Pilot.
//
// <!-- crd generation tags
// +cue-gen:EnvoyFilter:groupName:networking.istio.io
// +cue-gen:EnvoyFilter:version:v1alpha3
// +cue-gen:EnvoyFilter:storageVersion
// +cue-gen:EnvoyFilter:annotations:helm.sh/resource-policy=keep
// +cue-gen:EnvoyFilter:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
// +cue-gen:EnvoyFilter:subresource:status
// +cue-gen:EnvoyFilter:scope:Namespaced
// +cue-gen:EnvoyFilter:resource:categories=istio-io,networking-istio-io
// +cue-gen:EnvoyFilter:preserveUnknownFields:true
// -->
//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=networking.istio.io/v1alpha3
// +genclient
// +k8s:deepcopy-gen=true
// -->
message EnvoyFilter {
// `ApplyTo` specifies where in the Envoy configuration, the given patch should be applied.
enum ApplyTo {
INVALID = 0;
// Applies the patch to the listener.
LISTENER = 1;
// Applies the patch to the filter chain.
FILTER_CHAIN = 2;
// Applies the patch to the network filter chain, to modify an
// existing filter or add a new filter.
NETWORK_FILTER = 3;
// Applies the patch to the HTTP filter chain in the http
// connection manager, to modify an existing filter or add a new
// filter.
HTTP_FILTER = 4;
// Applies the patch to the Route configuration (rds output)
// inside a HTTP connection manager. This does not apply to the
// virtual host. Currently, only `MERGE` operation is allowed on the
// route configuration objects.
ROUTE_CONFIGURATION = 5;
// Applies the patch to a virtual host inside a route configuration.
VIRTUAL_HOST = 6;
// Applies the patch to a route object inside the matched virtual
// host in a route configuration.
HTTP_ROUTE = 7;
// Applies the patch to a cluster in a CDS output. Also used to add new clusters.
CLUSTER = 8;
// Applies the patch to or adds an extension config in ECDS output. Note that ECDS
// is only supported by HTTP filters.
EXTENSION_CONFIG = 9;
};
// PatchContext selects a class of configurations based on the
// traffic flow direction and workload type.
enum PatchContext {
// All listeners/routes/clusters in both sidecars and gateways.
ANY = 0;
// Inbound listener/route/cluster in sidecar.
SIDECAR_INBOUND = 1;
// Outbound listener/route/cluster in sidecar.
SIDECAR_OUTBOUND = 2;
// Gateway listener/route/cluster.
GATEWAY = 3;
};
// One or more properties of the proxy to match on.
message ProxyMatch {
// A regular expression in golang regex format (RE2) that can be
// used to select proxies using a specific version of istio
// proxy. The Istio version for a given proxy is obtained from the
// node metadata field `ISTIO_VERSION` supplied by the proxy when
// connecting to Pilot. This value is embedded as an environment
// variable (`ISTIO_META_ISTIO_VERSION`) in the Istio proxy docker
// image. Custom proxy implementations should provide this metadata
// variable to take advantage of the Istio version check option.
string proxy_version = 1;
// Match on the node metadata supplied by a proxy when connecting
// to Istio Pilot. Note that while Envoy's node metadata is of
// type Struct, only string key-value pairs are processed by
// Pilot. All keys specified in the metadata must match with exact
// values. The match will fail if any of the specified keys are
// absent or the values fail to match.
map<string, string> metadata = 2;
};
// Conditions specified in `ClusterMatch` must be met for the patch
// to be applied to a cluster.
message ClusterMatch {
// The service port for which this cluster was generated. If
// omitted, applies to clusters for any port.
uint32 port_number = 1;
// The fully qualified service name for this cluster. If omitted,
// applies to clusters for any service. For services defined
// through service entries, the service name is same as the hosts
// defined in the service entry.
string service = 2;
// The subset associated with the service. If omitted, applies to
// clusters for any subset of a service.
string subset = 3;
// The exact name of the cluster to match. To match a specific
// cluster by name, such as the internally generated `Passthrough`
// cluster, leave all fields in clusterMatch empty, except the
// name.
string name = 4;
};
// Conditions specified in RouteConfigurationMatch must be met for
// the patch to be applied to a route configuration object or a
// specific virtual host within the route configuration.
message RouteConfigurationMatch {
// Match a specific route inside a virtual host in a route configuration.
message RouteMatch {
// The Route objects generated by default are named as
// default. Route objects generated using a virtual service
// will carry the name used in the virtual service's HTTP
// routes.
string name = 1;
// Action refers to the route action taken by Envoy when a http route matches.
enum Action {
// All three route actions
ANY = 0;
// Route traffic to a cluster / weighted clusters.
ROUTE = 1;
// Redirect request.
REDIRECT = 2;
// directly respond to a request with specific payload.
DIRECT_RESPONSE = 3;
};
// Match a route with specific action type.
Action action = 2;
}
// Match a specific virtual host inside a route configuration.
message VirtualHostMatch {
// The VirtualHosts objects generated by Istio are named as
// host:port, where the host typically corresponds to the
// VirtualService's host field or the hostname of a service in the
// registry.
string name = 1;
// Match a specific route within the virtual host.
RouteMatch route = 2;
}
// The service port number or gateway server port number for which
// this route configuration was generated. If omitted, applies to
// route configurations for all ports.
uint32 port_number = 1;
// Applicable only for GATEWAY context. The gateway server port
// name for which this route configuration was generated.
string port_name = 2;
// The Istio gateway config's namespace/name for which this route
// configuration was generated. Applies only if the context is
// GATEWAY. Should be in the namespace/name format. Use this field
// in conjunction with the `portNumber` and `portName` to accurately
// select the Envoy route configuration for a specific HTTPS
// server within a gateway config object.
string gateway = 3;
// Match a specific virtual host in a route configuration and
// apply the patch to the virtual host.
VirtualHostMatch vhost = 4;
// Route configuration name to match on. Can be used to match a
// specific route configuration by name, such as the internally
// generated `http_proxy` route configuration for all sidecars.
string name = 5;
};
// Conditions specified in a listener match must be met for the
// patch to be applied to a specific listener across all filter
// chains, or a specific filter chain inside the listener.
message ListenerMatch {
// For listeners with multiple filter chains (e.g., inbound
// listeners on sidecars with permissive mTLS, gateway listeners
// with multiple SNI matches), the filter chain match can be used
// to select a specific filter chain to patch.
message FilterChainMatch {
// The name assigned to the filter chain.
string name = 1;
// The SNI value used by a filter chain's match condition. This
// condition will evaluate to false if the filter chain has no
// sni match.
string sni = 2;
// Applies only to `SIDECAR_INBOUND` context. If non-empty, a
// transport protocol to consider when determining a filter
// chain match. This value will be compared against the
// transport protocol of a new connection, when it's detected by
// the `tls_inspector` listener filter.
//
// Accepted values include:
//
// * `raw_buffer` - default, used when no transport protocol is detected.
// * `tls` - set when TLS protocol is detected by the TLS inspector.
string transport_protocol = 3;
// Applies only to sidecars. If non-empty, a comma separated set
// of application protocols to consider when determining a
// filter chain match. This value will be compared against the
// application protocols of a new connection, when it's detected
// by one of the listener filters such as the `http_inspector`.
//
// Accepted values include: h2, http/1.1, http/1.0
string application_protocols = 4;
// The name of a specific filter to apply the patch to. Set this
// to `envoy.filters.network.http_connection_manager` to add a filter or apply a
// patch to the HTTP connection manager.
FilterMatch filter = 5;
};
// Conditions to match a specific filter within a filter chain.
message FilterMatch {
// The filter name to match on.
// For standard Envoy filters, [canonical filter](https://www.envoyproxy.io/docs/envoy/latest/version_history/v1.14.0#deprecated)
// names should be used.
string name = 1;
// The next level filter within this filter to match
// upon. Typically used for HTTP Connection Manager filters and
// Thrift filters.
SubFilterMatch sub_filter = 2;
};
// Conditions to match a specific filter within another
// filter. This field is typically useful to match a HTTP filter
// inside the `envoy.filters.network.http_connection_manager` network filter.
// This could also be applicable for thrift filters.
message SubFilterMatch {
// The filter name to match on.
string name = 1;
};
// The service port/gateway port to which traffic is being
// sent/received. If not specified, matches all listeners. Even though
// inbound listeners are generated for the instance/pod ports, only
// service ports should be used to match listeners.
uint32 port_number = 1;
// Instead of using specific port numbers, a set of ports matching
// a given service's port name can be selected. Matching is case
// insensitive.
// Not implemented.
// $hide_from_docs
string port_name = 2;
// Match a specific filter chain in a listener. If specified, the
// patch will be applied to the filter chain (and a specific
// filter if specified) and not to other filter chains in the
// listener.
FilterChainMatch filter_chain = 3;
// Match a specific listener by its name. The listeners generated
// by Pilot are typically named as IP:Port.
string name = 4;
};
// Patch specifies how the selected object should be modified.
message Patch {
// Operation denotes how the patch should be applied to the selected
// configuration.
enum Operation {
INVALID = 0;
// Merge the provided config with the generated config using
// proto merge semantics. If you are specifying config in its
// entirity, use `REPLACE` instead.
MERGE = 1;
// Add the provided config to an existing list (of listeners,
// clusters, virtual hosts, network filters, or http
// filters). This operation will be ignored when `applyTo` is set
// to `ROUTE_CONFIGURATION`, or `HTTP_ROUTE`.
ADD = 2;
// Remove the selected object from the list (of listeners,
// clusters, virtual hosts, network filters, routes, or http
// filters). Does not require a value to be specified. This
// operation will be ignored when `applyTo` is set to
// `ROUTE_CONFIGURATION`, or `HTTP_ROUTE`.
REMOVE = 3;
// Insert operation on an array of named objects. This operation
// is typically useful only in the context of filters or routes,
// where the order of elements matter. Routes should be ordered
// based on most to least specific matching criteria since the
// first matching element is selected. For clusters and virtual hosts,
// order of the element in the array does not matter. Insert
// before the selected filter or sub filter. If no filter is
// selected, the specified filter will be inserted at the front
// of the list.
INSERT_BEFORE = 4;
// Insert operation on an array of named objects. This operation
// is typically useful only in the context of filters or routes,
// where the order of elements matter. Routes should be ordered
// based on most to least specific matching criteria since the
// first matching element is selected. For clusters and virtual hosts,
// order of the element in the array does not matter. Insert
// after the selected filter or sub filter. If no filter is
// selected, the specified filter will be inserted at the end
// of the list.
INSERT_AFTER = 5;
// Insert operation on an array of named objects. This operation
// is typically useful only in the context of filters or routes,
// where the order of elements matter. Routes should be ordered
// based on most to least specific matching criteria since the
// first matching element is selected. For clusters and virtual hosts,
// order of the element in the array does not matter. Insert
// first in the list based on the presence of selected filter or not.
// This is specifically useful when you want your filter first in the
// list based on a match condition specified in Match clause.
INSERT_FIRST = 6;
// Replace contents of a named filter with new contents.
// `REPLACE` operation is only valid for `HTTP_FILTER` and
// `NETWORK_FILTER`. If the named filter is not found, this operation
// has no effect.
REPLACE = 7;
}
// Determines how the patch should be applied.
Operation operation = 1;
// The JSON config of the object being patched. This will be merged using
// proto merge semantics with the existing proto in the path.
google.protobuf.Struct value = 2;
// FilterClass determines the filter insertion point in the filter chain
// relative to the filters implicitly inserted by the control plane.
// It is used in conjuction with the `ADD` operation.
// This is the preferred insertion mechanism for adding filters over
// the `INSERT_*` operations since those operations rely on potentially unstable
// filter names.
// Filter ordering is important if your filter depends on or affects the
// functioning of a another filter in the filter chain.
// Within a filter class, filters are inserted in the order of processing.
enum FilterClass {
// Control plane decides where to insert the filter.
// Do not specify `FilterClass` if the filter is independent of others.
UNSPECIFIED = 0;
// Insert filter after Istio authentication filters.
AUTHN = 1;
// Insert filter after Istio authorization filters.
AUTHZ = 2;
// Insert filter before Istio stats filters.
STATS = 3;
};
// Determines the filter insertion order.
FilterClass filter_class = 3;
};
// One or more match conditions to be met before a patch is applied
// to the generated configuration for a given proxy.
message EnvoyConfigObjectMatch {
// The specific config generation context to match on. Istio Pilot
// generates envoy configuration in the context of a gateway,
// inbound traffic to sidecar and outbound traffic from sidecar.
PatchContext context = 1;
// Match on properties associated with a proxy.
ProxyMatch proxy = 2;
oneof object_types {
// Match on envoy listener attributes.
ListenerMatch listener = 3;
// Match on envoy HTTP route configuration attributes.
RouteConfigurationMatch route_configuration = 4;
// Match on envoy cluster attributes.
ClusterMatch cluster = 5;
}
};
// Changes to be made to various envoy config objects.
message EnvoyConfigObjectPatch {
// Specifies where in the Envoy configuration, the patch should be
// applied. The match is expected to select the appropriate
// object based on applyTo. For example, an applyTo with
// `HTTP_FILTER` is expected to have a match condition on the
// listeners, with a network filter selection on
// `envoy.filters.network.http_connection_manager` and a sub filter selection on the
// HTTP filter relative to which the insertion should be
// performed. Similarly, an applyTo on `CLUSTER` should have a match
// (if provided) on the cluster and not on a listener.
ApplyTo apply_to = 1;
// Match on listener/route configuration/cluster.
EnvoyConfigObjectMatch match = 2;
// The patch to apply along with the operation.
Patch patch = 3;
}
reserved 1, 2;
reserved "filters", "workload_labels";
// Criteria used to select the specific set of pods/VMs on which
// this patch configuration should be applied. If omitted, the set
// of patches in this configuration will be applied to all workload
// instances in the same namespace. If omitted, the `EnvoyFilter`
// patches will be applied to all workloads in the same
// namespace. If the `EnvoyFilter` is present in the config root
// namespace, it will be applied to all applicable workloads in any
// namespace.
WorkloadSelector workload_selector = 3;
// One or more patches with match conditions.
repeated EnvoyConfigObjectPatch config_patches = 4 [(google.api.field_behavior) = REQUIRED];
}

View File

@ -0,0 +1,729 @@
// Copyright 2017 Istio Authors
//
// Licensed 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.
syntax = "proto3";
import "google/api/field_behavior.proto";
// $schema: istio.networking.v1alpha3.Gateway
// $title: Gateway
// $description: Configuration affecting edge load balancer.
// $location: https://istio.io/docs/reference/config/networking/gateway.html
// $aliases: [/docs/reference/config/networking/v1alpha3/gateway]
// `Gateway` describes a load balancer operating at the edge of the mesh
// receiving incoming or outgoing HTTP/TCP connections. The specification
// describes a set of ports that should be exposed, the type of protocol to
// use, SNI configuration for the load balancer, etc.
//
// For example, the following Gateway configuration sets up a proxy to act
// as a load balancer exposing port 80 and 9080 (http), 443 (https),
// 9443(https) and port 2379 (TCP) for ingress. The gateway will be
// applied to the proxy running on a pod with labels `app:
// my-gateway-controller`. While Istio will configure the proxy to listen
// on these ports, it is the responsibility of the user to ensure that
// external traffic to these ports are allowed into the mesh.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Gateway
// metadata:
// name: my-gateway
// namespace: some-config-namespace
// spec:
// selector:
// app: my-gateway-controller
// servers:
// - port:
// number: 80
// name: http
// protocol: HTTP
// hosts:
// - uk.bookinfo.com
// - eu.bookinfo.com
// tls:
// httpsRedirect: true # sends 301 redirect for http requests
// - port:
// number: 443
// name: https-443
// protocol: HTTPS
// hosts:
// - uk.bookinfo.com
// - eu.bookinfo.com
// tls:
// mode: SIMPLE # enables HTTPS on this port
// serverCertificate: /etc/certs/servercert.pem
// privateKey: /etc/certs/privatekey.pem
// - port:
// number: 9443
// name: https-9443
// protocol: HTTPS
// hosts:
// - "bookinfo-namespace/*.bookinfo.com"
// tls:
// mode: SIMPLE # enables HTTPS on this port
// credentialName: bookinfo-secret # fetches certs from Kubernetes secret
// - port:
// number: 9080
// name: http-wildcard
// protocol: HTTP
// hosts:
// - "*"
// - port:
// number: 2379 # to expose internal service via external port 2379
// name: mongo
// protocol: MONGO
// hosts:
// - "*"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Gateway
// metadata:
// name: my-gateway
// namespace: some-config-namespace
// spec:
// selector:
// app: my-gateway-controller
// servers:
// - port:
// number: 80
// name: http
// protocol: HTTP
// hosts:
// - uk.bookinfo.com
// - eu.bookinfo.com
// tls:
// httpsRedirect: true # sends 301 redirect for http requests
// - port:
// number: 443
// name: https-443
// protocol: HTTPS
// hosts:
// - uk.bookinfo.com
// - eu.bookinfo.com
// tls:
// mode: SIMPLE # enables HTTPS on this port
// serverCertificate: /etc/certs/servercert.pem
// privateKey: /etc/certs/privatekey.pem
// - port:
// number: 9443
// name: https-9443
// protocol: HTTPS
// hosts:
// - "bookinfo-namespace/*.bookinfo.com"
// tls:
// mode: SIMPLE # enables HTTPS on this port
// credentialName: bookinfo-secret # fetches certs from Kubernetes secret
// - port:
// number: 9080
// name: http-wildcard
// protocol: HTTP
// hosts:
// - "*"
// - port:
// number: 2379 # to expose internal service via external port 2379
// name: mongo
// protocol: MONGO
// hosts:
// - "*"
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The Gateway specification above describes the L4-L6 properties of a load
// balancer. A `VirtualService` can then be bound to a gateway to control
// the forwarding of traffic arriving at a particular host or gateway port.
//
// For example, the following VirtualService splits traffic for
// `https://uk.bookinfo.com/reviews`, `https://eu.bookinfo.com/reviews`,
// `http://uk.bookinfo.com:9080/reviews`,
// `http://eu.bookinfo.com:9080/reviews` into two versions (prod and qa) of
// an internal reviews service on port 9080. In addition, requests
// containing the cookie "user: dev-123" will be sent to special port 7777
// in the qa version. The same rule is also applicable inside the mesh for
// requests to the "reviews.prod.svc.cluster.local" service. This rule is
// applicable across ports 443, 9080. Note that `http://uk.bookinfo.com`
// gets redirected to `https://uk.bookinfo.com` (i.e. 80 redirects to 443).
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: VirtualService
// metadata:
// name: bookinfo-rule
// namespace: bookinfo-namespace
// spec:
// hosts:
// - reviews.prod.svc.cluster.local
// - uk.bookinfo.com
// - eu.bookinfo.com
// gateways:
// - some-config-namespace/my-gateway
// - mesh # applies to all the sidecars in the mesh
// http:
// - match:
// - headers:
// cookie:
// exact: "user=dev-123"
// route:
// - destination:
// port:
// number: 7777
// host: reviews.qa.svc.cluster.local
// - match:
// - uri:
// prefix: /reviews/
// route:
// - destination:
// port:
// number: 9080 # can be omitted if it's the only port for reviews
// host: reviews.prod.svc.cluster.local
// weight: 80
// - destination:
// host: reviews.qa.svc.cluster.local
// weight: 20
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: VirtualService
// metadata:
// name: bookinfo-rule
// namespace: bookinfo-namespace
// spec:
// hosts:
// - reviews.prod.svc.cluster.local
// - uk.bookinfo.com
// - eu.bookinfo.com
// gateways:
// - some-config-namespace/my-gateway
// - mesh # applies to all the sidecars in the mesh
// http:
// - match:
// - headers:
// cookie:
// exact: "user=dev-123"
// route:
// - destination:
// port:
// number: 7777
// host: reviews.qa.svc.cluster.local
// - match:
// - uri:
// prefix: /reviews/
// route:
// - destination:
// port:
// number: 9080 # can be omitted if it's the only port for reviews
// host: reviews.prod.svc.cluster.local
// weight: 80
// - destination:
// host: reviews.qa.svc.cluster.local
// weight: 20
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The following VirtualService forwards traffic arriving at (external)
// port 27017 to internal Mongo server on port 5555. This rule is not
// applicable internally in the mesh as the gateway list omits the
// reserved name `mesh`.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: VirtualService
// metadata:
// name: bookinfo-mongo
// namespace: bookinfo-namespace
// spec:
// hosts:
// - mongosvr.prod.svc.cluster.local # name of internal Mongo service
// gateways:
// - some-config-namespace/my-gateway # can omit the namespace if gateway is in same
// namespace as virtual service.
// tcp:
// - match:
// - port: 27017
// route:
// - destination:
// host: mongo.prod.svc.cluster.local
// port:
// number: 5555
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: VirtualService
// metadata:
// name: bookinfo-mongo
// namespace: bookinfo-namespace
// spec:
// hosts:
// - mongosvr.prod.svc.cluster.local # name of internal Mongo service
// gateways:
// - some-config-namespace/my-gateway # can omit the namespace if gateway is in same
// namespace as virtual service.
// tcp:
// - match:
// - port: 27017
// route:
// - destination:
// host: mongo.prod.svc.cluster.local
// port:
// number: 5555
// ```
// {{</tab>}}
// {{</tabset>}}
//
// It is possible to restrict the set of virtual services that can bind to
// a gateway server using the namespace/hostname syntax in the hosts field.
// For example, the following Gateway allows any virtual service in the ns1
// namespace to bind to it, while restricting only the virtual service with
// foo.bar.com host in the ns2 namespace to bind to it.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Gateway
// metadata:
// name: my-gateway
// namespace: some-config-namespace
// spec:
// selector:
// app: my-gateway-controller
// servers:
// - port:
// number: 80
// name: http
// protocol: HTTP
// hosts:
// - "ns1/*"
// - "ns2/foo.bar.com"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Gateway
// metadata:
// name: my-gateway
// namespace: some-config-namespace
// spec:
// selector:
// app: my-gateway-controller
// servers:
// - port:
// number: 80
// name: http
// protocol: HTTP
// hosts:
// - "ns1/*"
// - "ns2/foo.bar.com"
// ```
// {{</tab>}}
// {{</tabset>}}
//
package istio.networking.v1alpha3;
option go_package = "istio.io/api/networking/v1alpha3";
// Gateway describes a load balancer operating at the edge of the mesh
// receiving incoming or outgoing HTTP/TCP connections.
//
// <!-- crd generation tags
// +cue-gen:Gateway:groupName:networking.istio.io
// +cue-gen:Gateway:version:v1alpha3
// +cue-gen:Gateway:storageVersion
// +cue-gen:Gateway:annotations:helm.sh/resource-policy=keep
// +cue-gen:Gateway:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
// +cue-gen:Gateway:subresource:status
// +cue-gen:Gateway:scope:Namespaced
// +cue-gen:Gateway:resource:categories=istio-io,networking-istio-io,shortNames=gw
// +cue-gen:Gateway:preserveUnknownFields:false
// -->
//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=networking.istio.io/v1alpha3
// +genclient
// +k8s:deepcopy-gen=true
// -->
message Gateway {
// A list of server specifications.
repeated Server servers = 1 [(google.api.field_behavior) = REQUIRED];
// One or more labels that indicate a specific set of pods/VMs
// on which this gateway configuration should be applied.
// By default workloads are searched across all namespaces based on label selectors.
// This implies that a gateway resource in the namespace "foo" can select pods in
// the namespace "bar" based on labels.
// This behavior can be controlled via the `PILOT_SCOPE_GATEWAY_TO_NAMESPACE`
// environment variable in istiod. If this variable is set
// to true, the scope of label search is restricted to the configuration
// namespace in which the the resource is present. In other words, the Gateway
// resource must reside in the same namespace as the gateway workload
// instance.
// If selector is nil, the Gateway will be applied to all workloads.
map<string, string> selector = 2 [(google.api.field_behavior) = REQUIRED];
}
// `Server` describes the properties of the proxy on a given load balancer
// port. For example,
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Gateway
// metadata:
// name: my-ingress
// spec:
// selector:
// app: my-ingressgateway
// servers:
// - port:
// number: 80
// name: http2
// protocol: HTTP2
// hosts:
// - "*"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Gateway
// metadata:
// name: my-ingress
// spec:
// selector:
// app: my-ingressgateway
// servers:
// - port:
// number: 80
// name: http2
// protocol: HTTP2
// hosts:
// - "*"
// ```
// {{</tab>}}
// {{</tabset>}}
//
// Another example
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Gateway
// metadata:
// name: my-tcp-ingress
// spec:
// selector:
// app: my-tcp-ingressgateway
// servers:
// - port:
// number: 27018
// name: mongo
// protocol: MONGO
// hosts:
// - "*"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Gateway
// metadata:
// name: my-tcp-ingress
// spec:
// selector:
// app: my-tcp-ingressgateway
// servers:
// - port:
// number: 27018
// name: mongo
// protocol: MONGO
// hosts:
// - "*"
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The following is an example of TLS configuration for port 443
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Gateway
// metadata:
// name: my-tls-ingress
// spec:
// selector:
// app: my-tls-ingressgateway
// servers:
// - port:
// number: 443
// name: https
// protocol: HTTPS
// hosts:
// - "*"
// tls:
// mode: SIMPLE
// serverCertificate: /etc/certs/server.pem
// privateKey: /etc/certs/privatekey.pem
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Gateway
// metadata:
// name: my-tls-ingress
// spec:
// selector:
// app: my-tls-ingressgateway
// servers:
// - port:
// number: 443
// name: https
// protocol: HTTPS
// hosts:
// - "*"
// tls:
// mode: SIMPLE
// serverCertificate: /etc/certs/server.pem
// privateKey: /etc/certs/privatekey.pem
// ```
// {{</tab>}}
// {{</tabset>}}
//
message Server {
// The Port on which the proxy should listen for incoming
// connections.
Port port = 1 [(google.api.field_behavior) = REQUIRED];
// $hide_from_docs
// The ip or the Unix domain socket to which the listener should be bound
// to. Format: `x.x.x.x` or `unix:///path/to/uds` or `unix://@foobar`
// (Linux abstract namespace). When using Unix domain sockets, the port
// number should be 0.
string bind = 4;
// One or more hosts exposed by this gateway.
// While typically applicable to
// HTTP services, it can also be used for TCP services using TLS with SNI.
// A host is specified as a `dnsName` with an optional `namespace/` prefix.
// The `dnsName` should be specified using FQDN format, optionally including
// a wildcard character in the left-most component (e.g., `prod/*.example.com`).
// Set the `dnsName` to `*` to select all `VirtualService` hosts from the
// specified namespace (e.g.,`prod/*`).
//
// The `namespace` can be set to `*` or `.`, representing any or the current
// namespace, respectively. For example, `*/foo.example.com` selects the
// service from any available namespace while `./foo.example.com` only selects
// the service from the namespace of the sidecar. The default, if no `namespace/`
// is specified, is `*/`, that is, select services from any namespace.
// Any associated `DestinationRule` in the selected namespace will also be used.
//
// A `VirtualService` must be bound to the gateway and must have one or
// more hosts that match the hosts specified in a server. The match
// could be an exact match or a suffix match with the server's hosts. For
// example, if the server's hosts specifies `*.example.com`, a
// `VirtualService` with hosts `dev.example.com` or `prod.example.com` will
// match. However, a `VirtualService` with host `example.com` or
// `newexample.com` will not match.
//
// NOTE: Only virtual services exported to the gateway's namespace
// (e.g., `exportTo` value of `*`) can be referenced.
// Private configurations (e.g., `exportTo` set to `.`) will not be
// available. Refer to the `exportTo` setting in `VirtualService`,
// `DestinationRule`, and `ServiceEntry` configurations for details.
repeated string hosts = 2 [(google.api.field_behavior) = REQUIRED];
// Set of TLS related options that govern the server's behavior. Use
// these options to control if all http requests should be redirected to
// https, and the TLS modes to use.
ServerTLSSettings tls = 3;
// The loopback IP endpoint or Unix domain socket to which traffic should
// be forwarded to by default. Format should be `127.0.0.1:PORT` or
// `unix:///path/to/socket` or `unix://@foobar` (Linux abstract namespace).
// NOT IMPLEMENTED.
// $hide_from_docs
string default_endpoint = 5;
// An optional name of the server, when set must be unique across all servers.
// This will be used for variety of purposes like prefixing stats generated with
// this name etc.
string name = 6;
}
// Port describes the properties of a specific port of a service.
message Port {
// A valid non-negative integer port number.
uint32 number = 1 [(google.api.field_behavior) = REQUIRED];
// The protocol exposed on the port.
// MUST BE one of HTTP|HTTPS|GRPC|HTTP2|MONGO|TCP|TLS.
// TLS implies the connection will be routed based on the SNI header to
// the destination without terminating the TLS connection.
string protocol = 2 [(google.api.field_behavior) = REQUIRED];
// Label assigned to the port.
string name = 3 [(google.api.field_behavior) = REQUIRED];
// The port number on the endpoint where the traffic will be
// received. Applicable only when used with ServiceEntries.
uint32 target_port = 4;
}
message ServerTLSSettings {
// If set to true, the load balancer will send a 301 redirect for
// all http connections, asking the clients to use HTTPS.
bool https_redirect = 1;
// TLS modes enforced by the proxy
enum TLSmode {
// The SNI string presented by the client will be used as the
// match criterion in a VirtualService TLS route to determine
// the destination service from the service registry.
PASSTHROUGH = 0;
// Secure connections with standard TLS semantics.
SIMPLE = 1;
// Secure connections to the downstream using mutual TLS by
// presenting server certificates for authentication.
MUTUAL = 2;
// Similar to the passthrough mode, except servers with this TLS
// mode do not require an associated VirtualService to map from
// the SNI value to service in the registry. The destination
// details such as the service/subset/port are encoded in the
// SNI value. The proxy will forward to the upstream (Envoy)
// cluster (a group of endpoints) specified by the SNI
// value. This server is typically used to provide connectivity
// between services in disparate L3 networks that otherwise do
// not have direct connectivity between their respective
// endpoints. Use of this mode assumes that both the source and
// the destination are using Istio mTLS to secure traffic.
AUTO_PASSTHROUGH = 3;
// Secure connections from the downstream using mutual TLS by
// presenting server certificates for authentication. Compared
// to Mutual mode, this mode uses certificates, representing
// gateway workload identity, generated automatically by Istio
// for mTLS authentication. When this mode is used, all other
// fields in `TLSOptions` should be empty.
ISTIO_MUTUAL = 4;
};
// Optional: Indicates whether connections to this port should be
// secured using TLS. The value of this field determines how TLS is
// enforced.
TLSmode mode = 2;
// REQUIRED if mode is `SIMPLE` or `MUTUAL`. The path to the file
// holding the server-side TLS certificate to use.
string server_certificate = 3;
// REQUIRED if mode is `SIMPLE` or `MUTUAL`. The path to the file
// holding the server's private key.
string private_key = 4;
// REQUIRED if mode is `MUTUAL`. The path to a file containing
// certificate authority certificates to use in verifying a presented
// client side certificate.
string ca_certificates = 5;
// For gateways running on Kubernetes, the name of the secret that
// holds the TLS certs including the CA certificates. Applicable
// only on Kubernetes. The secret (of type `generic`) should
// contain the following keys and values: `key:
// <privateKey>` and `cert: <serverCert>`. For mutual TLS,
// `cacert: <CACertificate>` can be provided in the same secret or
// a separate secret named `<secret>-cacert`.
// Secret of type tls for server certificates along with
// ca.crt key for CA certificates is also supported.
// Only one of server certificates and CA certificate
// or credentialName can be specified.
string credential_name = 10;
// A list of alternate names to verify the subject identity in the
// certificate presented by the client.
repeated string subject_alt_names = 6;
// An optional list of base64-encoded SHA-256 hashes of the SKPIs of
// authorized client certificates.
// Note: When both verify_certificate_hash and verify_certificate_spki
// are specified, a hash matching either value will result in the
// certificate being accepted.
repeated string verify_certificate_spki = 11;
// An optional list of hex-encoded SHA-256 hashes of the
// authorized client certificates. Both simple and colon separated
// formats are acceptable.
// Note: When both verify_certificate_hash and verify_certificate_spki
// are specified, a hash matching either value will result in the
// certificate being accepted.
repeated string verify_certificate_hash = 12;
// TLS protocol versions.
enum TLSProtocol {
// Automatically choose the optimal TLS version.
TLS_AUTO = 0;
// TLS version 1.0
TLSV1_0 = 1;
// TLS version 1.1
TLSV1_1 = 2;
// TLS version 1.2
TLSV1_2 = 3;
// TLS version 1.3
TLSV1_3 = 4;
}
// Optional: Minimum TLS protocol version.
TLSProtocol min_protocol_version = 7;
// Optional: Maximum TLS protocol version.
TLSProtocol max_protocol_version = 8;
// Optional: If specified, only support the specified cipher list.
// Otherwise default to the default cipher list supported by Envoy.
repeated string cipher_suites = 9;
}

View File

@ -0,0 +1,957 @@
// Copyright 2018 Istio Authors
//
// Licensed 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.
syntax = "proto3";
import "google/api/field_behavior.proto";
import "networking/v1alpha3/gateway.proto";
import "networking/v1alpha3/sidecar.proto";
import "networking/v1alpha3/workload_entry.proto";
// $schema: istio.networking.v1alpha3.ServiceEntry
// $title: Service Entry
// $description: Configuration affecting service registry.
// $location: https://istio.io/docs/reference/config/networking/service-entry.html
// $aliases: [/docs/reference/config/networking/v1alpha3/service-entry]
// `ServiceEntry` enables adding additional entries into Istio's
// internal service registry, so that auto-discovered services in the
// mesh can access/route to these manually specified services. A
// service entry describes the properties of a service (DNS name,
// VIPs, ports, protocols, endpoints). These services could be
// external to the mesh (e.g., web APIs) or mesh-internal services
// that are not part of the platform's service registry (e.g., a set
// of VMs talking to services in Kubernetes). In addition, the
// endpoints of a service entry can also be dynamically selected by
// using the `workloadSelector` field. These endpoints can be VM
// workloads declared using the `WorkloadEntry` object or Kubernetes
// pods. The ability to select both pods and VMs under a single
// service allows for migration of services from VMs to Kubernetes
// without having to change the existing DNS names associated with the
// services.
//
// The following example declares a few external APIs accessed by internal
// applications over HTTPS. The sidecar inspects the SNI value in the
// ClientHello message to route to the appropriate external service.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: external-svc-https
// spec:
// hosts:
// - api.dropboxapi.com
// - www.googleapis.com
// - api.facebook.com
// location: MESH_EXTERNAL
// ports:
// - number: 443
// name: https
// protocol: TLS
// resolution: DNS
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: external-svc-https
// spec:
// hosts:
// - api.dropboxapi.com
// - www.googleapis.com
// - api.facebook.com
// location: MESH_EXTERNAL
// ports:
// - number: 443
// name: https
// protocol: TLS
// resolution: DNS
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The following configuration adds a set of MongoDB instances running on
// unmanaged VMs to Istio's registry, so that these services can be treated
// as any other service in the mesh. The associated DestinationRule is used
// to initiate mTLS connections to the database instances.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: external-svc-mongocluster
// spec:
// hosts:
// - mymongodb.somedomain # not used
// addresses:
// - 192.192.192.192/24 # VIPs
// ports:
// - number: 27018
// name: mongodb
// protocol: MONGO
// location: MESH_INTERNAL
// resolution: STATIC
// endpoints:
// - address: 2.2.2.2
// - address: 3.3.3.3
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: external-svc-mongocluster
// spec:
// hosts:
// - mymongodb.somedomain # not used
// addresses:
// - 192.192.192.192/24 # VIPs
// ports:
// - number: 27018
// name: mongodb
// protocol: MONGO
// location: MESH_INTERNAL
// resolution: STATIC
// endpoints:
// - address: 2.2.2.2
// - address: 3.3.3.3
// ```
// {{</tab>}}
// {{</tabset>}}
//
// and the associated DestinationRule
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: DestinationRule
// metadata:
// name: mtls-mongocluster
// spec:
// host: mymongodb.somedomain
// trafficPolicy:
// tls:
// mode: MUTUAL
// clientCertificate: /etc/certs/myclientcert.pem
// privateKey: /etc/certs/client_private_key.pem
// caCertificates: /etc/certs/rootcacerts.pem
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: DestinationRule
// metadata:
// name: mtls-mongocluster
// spec:
// host: mymongodb.somedomain
// trafficPolicy:
// tls:
// mode: MUTUAL
// clientCertificate: /etc/certs/myclientcert.pem
// privateKey: /etc/certs/client_private_key.pem
// caCertificates: /etc/certs/rootcacerts.pem
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The following example uses a combination of service entry and TLS
// routing in a virtual service to steer traffic based on the SNI value to
// an internal egress firewall.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: external-svc-redirect
// spec:
// hosts:
// - wikipedia.org
// - "*.wikipedia.org"
// location: MESH_EXTERNAL
// ports:
// - number: 443
// name: https
// protocol: TLS
// resolution: NONE
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: external-svc-redirect
// spec:
// hosts:
// - wikipedia.org
// - "*.wikipedia.org"
// location: MESH_EXTERNAL
// ports:
// - number: 443
// name: https
// protocol: TLS
// resolution: NONE
// ```
// {{</tab>}}
// {{</tabset>}}
//
// And the associated VirtualService to route based on the SNI value.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: VirtualService
// metadata:
// name: tls-routing
// spec:
// hosts:
// - wikipedia.org
// - "*.wikipedia.org"
// tls:
// - match:
// - sniHosts:
// - wikipedia.org
// - "*.wikipedia.org"
// route:
// - destination:
// host: internal-egress-firewall.ns1.svc.cluster.local
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: VirtualService
// metadata:
// name: tls-routing
// spec:
// hosts:
// - wikipedia.org
// - "*.wikipedia.org"
// tls:
// - match:
// - sniHosts:
// - wikipedia.org
// - "*.wikipedia.org"
// route:
// - destination:
// host: internal-egress-firewall.ns1.svc.cluster.local
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The virtual service with TLS match serves to override the default SNI
// match. In the absence of a virtual service, traffic will be forwarded to
// the wikipedia domains.
//
// The following example demonstrates the use of a dedicated egress gateway
// through which all external service traffic is forwarded.
// The 'exportTo' field allows for control over the visibility of a service
// declaration to other namespaces in the mesh. By default, a service is exported
// to all namespaces. The following example restricts the visibility to the
// current namespace, represented by ".", so that it cannot be used by other
// namespaces.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: external-svc-httpbin
// namespace : egress
// spec:
// hosts:
// - httpbin.com
// exportTo:
// - "."
// location: MESH_EXTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: DNS
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: external-svc-httpbin
// namespace : egress
// spec:
// hosts:
// - httpbin.com
// exportTo:
// - "."
// location: MESH_EXTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: DNS
// ```
// {{</tab>}}
// {{</tabset>}}
//
// Define a gateway to handle all egress traffic.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Gateway
// metadata:
// name: istio-egressgateway
// namespace: istio-system
// spec:
// selector:
// istio: egressgateway
// servers:
// - port:
// number: 80
// name: http
// protocol: HTTP
// hosts:
// - "*"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Gateway
// metadata:
// name: istio-egressgateway
// namespace: istio-system
// spec:
// selector:
// istio: egressgateway
// servers:
// - port:
// number: 80
// name: http
// protocol: HTTP
// hosts:
// - "*"
// ```
// {{</tab>}}
// {{</tabset>}}
//
// And the associated `VirtualService` to route from the sidecar to the
// gateway service (`istio-egressgateway.istio-system.svc.cluster.local`), as
// well as route from the gateway to the external service. Note that the
// virtual service is exported to all namespaces enabling them to route traffic
// through the gateway to the external service. Forcing traffic to go through
// a managed middle proxy like this is a common practice.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: VirtualService
// metadata:
// name: gateway-routing
// namespace: egress
// spec:
// hosts:
// - httpbin.com
// exportTo:
// - "*"
// gateways:
// - mesh
// - istio-egressgateway
// http:
// - match:
// - port: 80
// gateways:
// - mesh
// route:
// - destination:
// host: istio-egressgateway.istio-system.svc.cluster.local
// - match:
// - port: 80
// gateways:
// - istio-egressgateway
// route:
// - destination:
// host: httpbin.com
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: VirtualService
// metadata:
// name: gateway-routing
// namespace: egress
// spec:
// hosts:
// - httpbin.com
// exportTo:
// - "*"
// gateways:
// - mesh
// - istio-egressgateway
// http:
// - match:
// - port: 80
// gateways:
// - mesh
// route:
// - destination:
// host: istio-egressgateway.istio-system.svc.cluster.local
// - match:
// - port: 80
// gateways:
// - istio-egressgateway
// route:
// - destination:
// host: httpbin.com
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The following example demonstrates the use of wildcards in the hosts for
// external services. If the connection has to be routed to the IP address
// requested by the application (i.e. application resolves DNS and attempts
// to connect to a specific IP), the discovery mode must be set to `NONE`.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: external-svc-wildcard-example
// spec:
// hosts:
// - "*.bar.com"
// location: MESH_EXTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: NONE
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: external-svc-wildcard-example
// spec:
// hosts:
// - "*.bar.com"
// location: MESH_EXTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: NONE
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The following example demonstrates a service that is available via a
// Unix Domain Socket on the host of the client. The resolution must be
// set to STATIC to use Unix address endpoints.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: unix-domain-socket-example
// spec:
// hosts:
// - "example.unix.local"
// location: MESH_EXTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: STATIC
// endpoints:
// - address: unix:///var/run/example/socket
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: unix-domain-socket-example
// spec:
// hosts:
// - "example.unix.local"
// location: MESH_EXTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: STATIC
// endpoints:
// - address: unix:///var/run/example/socket
// ```
// {{</tab>}}
// {{</tabset>}}
//
// For HTTP-based services, it is possible to create a `VirtualService`
// backed by multiple DNS addressable endpoints. In such a scenario, the
// application can use the `HTTP_PROXY` environment variable to transparently
// reroute API calls for the `VirtualService` to a chosen backend. For
// example, the following configuration creates a non-existent external
// service called foo.bar.com backed by three domains: us.foo.bar.com:8080,
// uk.foo.bar.com:9080, and in.foo.bar.com:7080
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: external-svc-dns
// spec:
// hosts:
// - foo.bar.com
// location: MESH_EXTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: DNS
// endpoints:
// - address: us.foo.bar.com
// ports:
// http: 8080
// - address: uk.foo.bar.com
// ports:
// http: 9080
// - address: in.foo.bar.com
// ports:
// http: 7080
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: external-svc-dns
// spec:
// hosts:
// - foo.bar.com
// location: MESH_EXTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: DNS
// endpoints:
// - address: us.foo.bar.com
// ports:
// https: 8080
// - address: uk.foo.bar.com
// ports:
// https: 9080
// - address: in.foo.bar.com
// ports:
// https: 7080
// ```
// {{</tab>}}
// {{</tabset>}}
//
// With `HTTP_PROXY=http://localhost/`, calls from the application to
// `http://foo.bar.com` will be load balanced across the three domains
// specified above. In other words, a call to `http://foo.bar.com/baz` would
// be translated to `http://uk.foo.bar.com/baz`.
//
// The following example illustrates the usage of a `ServiceEntry`
// containing a subject alternate name
// whose format conforms to the [SPIFFE standard](https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md):
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: httpbin
// namespace : httpbin-ns
// spec:
// hosts:
// - httpbin.com
// location: MESH_INTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: STATIC
// endpoints:
// - address: 2.2.2.2
// - address: 3.3.3.3
// subjectAltNames:
// - "spiffe://cluster.local/ns/httpbin-ns/sa/httpbin-service-account"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: httpbin
// namespace : httpbin-ns
// spec:
// hosts:
// - httpbin.com
// location: MESH_INTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: STATIC
// endpoints:
// - address: 2.2.2.2
// - address: 3.3.3.3
// subjectAltNames:
// - "spiffe://cluster.local/ns/httpbin-ns/sa/httpbin-service-account"
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The following example demonstrates the use of `ServiceEntry` with a
// `workloadSelector` to handle the migration of a service
// `details.bookinfo.com` from VMs to Kubernetes. The service has two
// VM-based instances with sidecars as well as a set of Kubernetes
// pods managed by a standard deployment object. Consumers of this
// service in the mesh will be automatically load balanced across the
// VMs and Kubernetes. VM for the `details.bookinfo.com`
// service. This VM has sidecar installed and bootstrapped using the
// `details-legacy` service account. The sidecar receives HTTP traffic
// on port 80 (wrapped in istio mutual TLS) and forwards it to the
// application on the localhost on the same port.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: WorkloadEntry
// metadata:
// name: details-vm-1
// spec:
// serviceAccount: details
// address: 2.2.2.2
// labels:
// app: details
// instance-id: vm1
// ---
// apiVersion: networking.istio.io/v1alpha3
// kind: WorkloadEntry
// metadata:
// name: details-vm-2
// spec:
// serviceAccount: details
// address: 3.3.3.3
// labels:
// app: details
// instance-id: vm2
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: WorkloadEntry
// metadata:
// name: details-vm-1
// spec:
// serviceAccount: details
// address: 2.2.2.2
// labels:
// app: details
// instance-id: vm1
// ---
// apiVersion: networking.istio.io/v1beta1
// kind: WorkloadEntry
// metadata:
// name: details-vm-2
// spec:
// serviceAccount: details
// address: 3.3.3.3
// labels:
// app: details
// instance-id: vm2
// ```
// {{</tab>}}
// {{</tabset>}}
//
// Assuming there is also a Kubernetes deployment with pod labels
// `app: details` using the same service account `details`, the
// following service entry declares a service spanning both VMs and
// Kubernetes:
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: details-svc
// spec:
// hosts:
// - details.bookinfo.com
// location: MESH_INTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: STATIC
// workloadSelector:
// labels:
// app: details
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: details-svc
// spec:
// hosts:
// - details.bookinfo.com
// location: MESH_INTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// resolution: STATIC
// workloadSelector:
// labels:
// app: details
// ```
// {{</tab>}}
// {{</tabset>}}
package istio.networking.v1alpha3;
option go_package = "istio.io/api/networking/v1alpha3";
// ServiceEntry enables adding additional entries into Istio's internal
// service registry.
//
// <!-- crd generation tags
// +cue-gen:ServiceEntry:groupName:networking.istio.io
// +cue-gen:ServiceEntry:version:v1alpha3
// +cue-gen:ServiceEntry:storageVersion
// +cue-gen:ServiceEntry:annotations:helm.sh/resource-policy=keep
// +cue-gen:ServiceEntry:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
// +cue-gen:ServiceEntry:subresource:status
// +cue-gen:ServiceEntry:scope:Namespaced
// +cue-gen:ServiceEntry:resource:categories=istio-io,networking-istio-io,shortNames=se,plural=serviceentries
// +cue-gen:ServiceEntry:printerColumn:name=Hosts,type=string,JSONPath=.spec.hosts,description="The hosts associated with the ServiceEntry"
// +cue-gen:ServiceEntry:printerColumn:name=Location,type=string,JSONPath=.spec.location,description="Whether the service is external to the
// mesh or part of the mesh (MESH_EXTERNAL or MESH_INTERNAL)"
// +cue-gen:ServiceEntry:printerColumn:name=Resolution,type=string,JSONPath=.spec.resolution,description="Service discovery mode for the hosts
// (NONE, STATIC, or DNS)"
// +cue-gen:ServiceEntry:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
// representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
// Clients may not set this value. It is represented in RFC3339 form and is in UTC.
// Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
// +cue-gen:ServiceEntry:preserveUnknownFields:false
// -->
//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=networking.istio.io/v1alpha3
// +genclient
// +k8s:deepcopy-gen=true
// -->
message ServiceEntry {
// The hosts associated with the ServiceEntry. Could be a DNS
// name with wildcard prefix.
//
// 1. The hosts field is used to select matching hosts in VirtualServices and DestinationRules.
// 2. For HTTP traffic the HTTP Host/Authority header will be matched against the hosts field.
// 3. For HTTPs or TLS traffic containing Server Name Indication (SNI), the SNI value
// will be matched against the hosts field.
//
// **NOTE 1:** When resolution is set to type DNS and no endpoints
// are specified, the host field will be used as the DNS name of the
// endpoint to route traffic to.
//
// **NOTE 2:** If the hostname matches with the name of a service
// from another service registry such as Kubernetes that also
// supplies its own set of endpoints, the ServiceEntry will be
// treated as a decorator of the existing Kubernetes
// service. Properties in the service entry will be added to the
// Kubernetes service if applicable. Currently, the only the
// following additional properties will be considered by `istiod`:
//
// 1. subjectAltNames: In addition to verifying the SANs of the
// service accounts associated with the pods of the service, the
// SANs specified here will also be verified.
//
repeated string hosts = 1 [(google.api.field_behavior) = REQUIRED];
// The virtual IP addresses associated with the service. Could be CIDR
// prefix. For HTTP traffic, generated route configurations will include http route
// domains for both the `addresses` and `hosts` field values and the destination will
// be identified based on the HTTP Host/Authority header.
// If one or more IP addresses are specified,
// the incoming traffic will be identified as belonging to this service
// if the destination IP matches the IP/CIDRs specified in the addresses
// field. If the Addresses field is empty, traffic will be identified
// solely based on the destination port. In such scenarios, the port on
// which the service is being accessed must not be shared by any other
// service in the mesh. In other words, the sidecar will behave as a
// simple TCP proxy, forwarding incoming traffic on a specified port to
// the specified destination endpoint IP/host. Unix domain socket
// addresses are not supported in this field.
repeated string addresses = 2;
// The ports associated with the external service. If the
// Endpoints are Unix domain socket addresses, there must be exactly one
// port.
repeated Port ports = 3 [(google.api.field_behavior) = REQUIRED];
// Location specifies whether the service is part of Istio mesh or
// outside the mesh. Location determines the behavior of several
// features, such as service-to-service mTLS authentication, policy
// enforcement, etc. When communicating with services outside the mesh,
// Istio's mTLS authentication is disabled, and policy enforcement is
// performed on the client-side as opposed to server-side.
enum Location {
// Signifies that the service is external to the mesh. Typically used
// to indicate external services consumed through APIs.
MESH_EXTERNAL = 0;
// Signifies that the service is part of the mesh. Typically used to
// indicate services added explicitly as part of expanding the service
// mesh to include unmanaged infrastructure (e.g., VMs added to a
// Kubernetes based service mesh).
MESH_INTERNAL = 1;
};
// Specify whether the service should be considered external to the mesh
// or part of the mesh.
Location location = 4;
// Resolution determines how the proxy will resolve the IP addresses of
// the network endpoints associated with the service, so that it can
// route to one of them. The resolution mode specified here has no impact
// on how the application resolves the IP address associated with the
// service. The application may still have to use DNS to resolve the
// service to an IP so that the outbound traffic can be captured by the
// Proxy. Alternatively, for HTTP services, the application could
// directly communicate with the proxy (e.g., by setting HTTP_PROXY) to
// talk to these services.
enum Resolution {
// Assume that incoming connections have already been resolved (to a
// specific destination IP address). Such connections are typically
// routed via the proxy using mechanisms such as IP table REDIRECT/
// eBPF. After performing any routing related transformations, the
// proxy will forward the connection to the IP address to which the
// connection was bound.
NONE = 0;
// Use the static IP addresses specified in endpoints (see below) as the
// backing instances associated with the service.
STATIC = 1;
// Attempt to resolve the IP address by querying the ambient DNS,
// during request processing. If no endpoints are specified, the proxy
// will resolve the DNS address specified in the hosts field, if
// wildcards are not used. If endpoints are specified, the DNS
// addresses specified in the endpoints will be resolved to determine
// the destination IP address. DNS resolution cannot be used with Unix
// domain socket endpoints.
DNS = 2;
};
// Service discovery mode for the hosts. Care must be taken
// when setting the resolution mode to NONE for a TCP port without
// accompanying IP addresses. In such cases, traffic to any IP on
// said port will be allowed (i.e. `0.0.0.0:<port>`).
Resolution resolution = 5 [(google.api.field_behavior) = REQUIRED];
// One or more endpoints associated with the service. Only one of
// `endpoints` or `workloadSelector` can be specified.
repeated WorkloadEntry endpoints = 6;
// Applicable only for MESH_INTERNAL services. Only one of
// `endpoints` or `workloadSelector` can be specified. Selects one
// or more Kubernetes pods or VM workloads (specified using
// `WorkloadEntry`) based on their labels. The `WorkloadEntry` object
// representing the VMs should be defined in the same namespace as
// the ServiceEntry.
WorkloadSelector workload_selector = 9;
// A list of namespaces to which this service is exported. Exporting a service
// allows it to be used by sidecars, gateways and virtual services defined in
// other namespaces. This feature provides a mechanism for service owners
// and mesh administrators to control the visibility of services across
// namespace boundaries.
//
// If no namespaces are specified then the service is exported to all
// namespaces by default.
//
// The value "." is reserved and defines an export to the same namespace that
// the service is declared in. Similarly the value "*" is reserved and
// defines an export to all namespaces.
//
// For a Kubernetes Service, the equivalent effect can be achieved by setting
// the annotation "networking.istio.io/exportTo" to a comma-separated list
// of namespace names.
//
// NOTE: in the current release, the `exportTo` value is restricted to
// "." or "*" (i.e., the current namespace or all namespaces).
repeated string export_to = 7;
// If specified, the proxy will verify that the server certificate's
// subject alternate name matches one of the specified values.
//
// NOTE: When using the workloadEntry with workloadSelectors, the
// service account specified in the workloadEntry will also be used
// to derive the additional subject alternate names that should be
// verified.
repeated string subject_alt_names = 8;
}

View File

@ -0,0 +1,639 @@
// Copyright 2018 Istio Authors
//
// Licensed 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.
syntax = "proto3";
import "google/api/field_behavior.proto";
import "networking/v1alpha3/gateway.proto";
import "networking/v1alpha3/virtual_service.proto";
import "networking/v1alpha3/destination_rule.proto";
// $schema: istio.networking.v1alpha3.Sidecar
// $title: Sidecar
// $description: Configuration affecting network reachability of a sidecar.
// $location: https://istio.io/docs/reference/config/networking/sidecar.html
// $aliases: [/docs/reference/config/networking/v1alpha3/sidecar]
// `Sidecar` describes the configuration of the sidecar proxy that mediates
// inbound and outbound communication to the workload instance it is attached to. By
// default, Istio will program all sidecar proxies in the mesh with the
// necessary configuration required to reach every workload instance in the mesh, as
// well as accept traffic on all the ports associated with the
// workload. The `Sidecar` configuration provides a way to fine tune the set of
// ports, protocols that the proxy will accept when forwarding traffic to
// and from the workload. In addition, it is possible to restrict the set
// of services that the proxy can reach when forwarding outbound traffic
// from workload instances.
//
// Services and configuration in a mesh are organized into one or more
// namespaces (e.g., a Kubernetes namespace or a CF org/space). A `Sidecar`
// configuration in a namespace will apply to one or more workload instances in the same
// namespace, selected using the `workloadSelector` field. In the absence of a
// `workloadSelector`, it will apply to all workload instances in the same
// namespace. When determining the `Sidecar` configuration to be applied to a
// workload instance, preference will be given to the resource with a
// `workloadSelector` that selects this workload instance, over a `Sidecar` configuration
// without any `workloadSelector`.
//
// **NOTE 1**: *_Each namespace can have only one `Sidecar`
// configuration without any `workloadSelector`_ that specifies the
// default for all pods in that namespace*. It is recommended to use
// the name `default` for the namespace-wide sidecar. The behavior of
// the system is undefined if more than one selector-less `Sidecar`
// configurations exist in a given namespace. The behavior of the
// system is undefined if two or more `Sidecar` configurations with a
// `workloadSelector` select the same workload instance.
//
// **NOTE 2**: *_A `Sidecar` configuration in the `MeshConfig`
// [root namespace](https://istio.io/docs/reference/config/istio.mesh.v1alpha1/#MeshConfig)
// will be applied by default to all namespaces without a `Sidecar`
// configuration_*. This global default `Sidecar` configuration should not have
// any `workloadSelector`.
//
// The example below declares a global default `Sidecar` configuration
// in the root namespace called `istio-config`, that configures
// sidecars in all namespaces to allow egress traffic only to other
// workloads in the same namespace as well as to services in the
// `istio-system` namespace.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Sidecar
// metadata:
// name: default
// namespace: istio-config
// spec:
// egress:
// - hosts:
// - "./*"
// - "istio-system/*"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Sidecar
// metadata:
// name: default
// namespace: istio-config
// spec:
// egress:
// - hosts:
// - "./*"
// - "istio-system/*"
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The example below declares a `Sidecar` configuration in the
// `prod-us1` namespace that overrides the global default defined
// above, and configures the sidecars in the namespace to allow egress
// traffic to public services in the `prod-us1`, `prod-apis`, and the
// `istio-system` namespaces.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Sidecar
// metadata:
// name: default
// namespace: prod-us1
// spec:
// egress:
// - hosts:
// - "prod-us1/*"
// - "prod-apis/*"
// - "istio-system/*"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Sidecar
// metadata:
// name: default
// namespace: prod-us1
// spec:
// egress:
// - hosts:
// - "prod-us1/*"
// - "prod-apis/*"
// - "istio-system/*"
// ```
// {{</tab>}}
// {{</tabset>}}
//
// The following example declares a `Sidecar` configuration in the
// `prod-us1` namespace for all pods with labels `app: ratings`
// belonging to the `ratings.prod-us1` service. The workload accepts
// inbound HTTP traffic on port 9080. The traffic is then forwarded to
// the attached workload instance listening on a Unix domain
// socket. In the egress direction, in addition to the `istio-system`
// namespace, the sidecar proxies only HTTP traffic bound for port
// 9080 for services in the `prod-us1` namespace.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Sidecar
// metadata:
// name: ratings
// namespace: prod-us1
// spec:
// workloadSelector:
// labels:
// app: ratings
// ingress:
// - port:
// number: 9080
// protocol: HTTP
// name: somename
// defaultEndpoint: unix:///var/run/someuds.sock
// egress:
// - port:
// number: 9080
// protocol: HTTP
// name: egresshttp
// hosts:
// - "prod-us1/*"
// - hosts:
// - "istio-system/*"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Sidecar
// metadata:
// name: ratings
// namespace: prod-us1
// spec:
// workloadSelector:
// labels:
// app: ratings
// ingress:
// - port:
// number: 9080
// protocol: HTTP
// name: somename
// defaultEndpoint: unix:///var/run/someuds.sock
// egress:
// - port:
// number: 9080
// protocol: HTTP
// name: egresshttp
// hosts:
// - "prod-us1/*"
// - hosts:
// - "istio-system/*"
// ```
// {{</tab>}}
// {{</tabset>}}
//
// If the workload is deployed without IPTables-based traffic capture,
// the `Sidecar` configuration is the only way to configure the ports
// on the proxy attached to the workload instance. The following
// example declares a `Sidecar` configuration in the `prod-us1`
// namespace for all pods with labels `app: productpage` belonging to
// the `productpage.prod-us1` service. Assuming that these pods are
// deployed without IPtable rules (i.e. the `istio-init` container)
// and the proxy metadata `ISTIO_META_INTERCEPTION_MODE` is set to
// `NONE`, the specification, below, allows such pods to receive HTTP
// traffic on port 9080 (wrapped inside Istio mutual TLS) and forward
// it to the application listening on `127.0.0.1:8080`. It also allows
// the application to communicate with a backing MySQL database on
// `127.0.0.1:3306`, that then gets proxied to the externally hosted
// MySQL service at `mysql.foo.com:3306`.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Sidecar
// metadata:
// name: no-ip-tables
// namespace: prod-us1
// spec:
// workloadSelector:
// labels:
// app: productpage
// ingress:
// - port:
// number: 9080 # binds to proxy_instance_ip:9080 (0.0.0.0:9080, if no unicast IP is available for the instance)
// protocol: HTTP
// name: somename
// defaultEndpoint: 127.0.0.1:8080
// captureMode: NONE # not needed if metadata is set for entire proxy
// egress:
// - port:
// number: 3306
// protocol: MYSQL
// name: egressmysql
// captureMode: NONE # not needed if metadata is set for entire proxy
// bind: 127.0.0.1
// hosts:
// - "*/mysql.foo.com"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Sidecar
// metadata:
// name: no-ip-tables
// namespace: prod-us1
// spec:
// workloadSelector:
// labels:
// app: productpage
// ingress:
// - port:
// number: 9080 # binds to proxy_instance_ip:9080 (0.0.0.0:9080, if no unicast IP is available for the instance)
// protocol: HTTP
// name: somename
// defaultEndpoint: 127.0.0.1:8080
// captureMode: NONE # not needed if metadata is set for entire proxy
// egress:
// - port:
// number: 3306
// protocol: MYSQL
// name: egressmysql
// captureMode: NONE # not needed if metadata is set for entire proxy
// bind: 127.0.0.1
// hosts:
// - "*/mysql.foo.com"
// ```
// {{</tab>}}
// {{</tabset>}}
//
// And the associated service entry for routing to `mysql.foo.com:3306`
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: external-svc-mysql
// namespace: ns1
// spec:
// hosts:
// - mysql.foo.com
// ports:
// - number: 3306
// name: mysql
// protocol: MYSQL
// location: MESH_EXTERNAL
// resolution: DNS
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: external-svc-mysql
// namespace: ns1
// spec:
// hosts:
// - mysql.foo.com
// ports:
// - number: 3306
// name: mysql
// protocol: MYSQL
// location: MESH_EXTERNAL
// resolution: DNS
// ```
// {{</tab>}}
// {{</tabset>}}
//
// It is also possible to mix and match traffic capture modes in a single
// proxy. For example, consider a setup where internal services are on the
// `192.168.0.0/16` subnet. So, IP tables are setup on the VM to capture all
// outbound traffic on `192.168.0.0/16` subnet. Assume that the VM has an
// additional network interface on `172.16.0.0/16` subnet for inbound
// traffic. The following `Sidecar` configuration allows the VM to expose a
// listener on `172.16.1.32:80` (the VM's IP) for traffic arriving from the
// `172.16.0.0/16` subnet.
//
// **NOTE**: The `ISTIO_META_INTERCEPTION_MODE` metadata on the
// proxy in the VM should contain `REDIRECT` or `TPROXY` as its value,
// implying that IP tables based traffic capture is active.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: Sidecar
// metadata:
// name: partial-ip-tables
// namespace: prod-us1
// spec:
// workloadSelector:
// labels:
// app: productpage
// ingress:
// - bind: 172.16.1.32
// port:
// number: 80 # binds to 172.16.1.32:80
// protocol: HTTP
// name: somename
// defaultEndpoint: 127.0.0.1:8080
// captureMode: NONE
// egress:
// # use the system detected defaults
// # sets up configuration to handle outbound traffic to services
// # in 192.168.0.0/16 subnet, based on information provided by the
// # service registry
// - captureMode: IPTABLES
// hosts:
// - "*/*"
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: Sidecar
// metadata:
// name: partial-ip-tables
// namespace: prod-us1
// spec:
// workloadSelector:
// labels:
// app: productpage
// ingress:
// - bind: 172.16.1.32
// port:
// number: 80 # binds to 172.16.1.32:80
// protocol: HTTP
// name: somename
// defaultEndpoint: 127.0.0.1:8080
// captureMode: NONE
// egress:
// # use the system detected defaults
// # sets up configuration to handle outbound traffic to services
// # in 192.168.0.0/16 subnet, based on information provided by the
// # service registry
// - captureMode: IPTABLES
// hosts:
// - "*/*"
// ```
// {{</tab>}}
// {{</tabset>}}
//
package istio.networking.v1alpha3;
option go_package = "istio.io/api/networking/v1alpha3";
// `Sidecar` describes the configuration of the sidecar proxy that mediates
// inbound and outbound communication of the workload instance to which it is
// attached.
//
// <!-- crd generation tags
// +cue-gen:Sidecar:groupName:networking.istio.io
// +cue-gen:Sidecar:version:v1alpha3
// +cue-gen:Sidecar:storageVersion
// +cue-gen:Sidecar:annotations:helm.sh/resource-policy=keep
// +cue-gen:Sidecar:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
// +cue-gen:Sidecar:subresource:status
// +cue-gen:Sidecar:scope:Namespaced
// +cue-gen:Sidecar:resource:categories=istio-io,networking-istio-io
// +cue-gen:Sidecar:preserveUnknownFields:false
// -->
//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=networking.istio.io/v1alpha3
// +genclient
// +k8s:deepcopy-gen=true
// -->
message Sidecar {
// Criteria used to select the specific set of pods/VMs on which this
// `Sidecar` configuration should be applied. If omitted, the `Sidecar`
// configuration will be applied to all workload instances in the same namespace.
WorkloadSelector workload_selector = 1;
// Ingress specifies the configuration of the sidecar for processing
// inbound traffic to the attached workload instance. If omitted, Istio will
// automatically configure the sidecar based on the information about the workload
// obtained from the orchestration platform (e.g., exposed ports, services,
// etc.). If specified, inbound ports are configured if and only if the
// workload instance is associated with a service.
repeated IstioIngressListener ingress = 2;
// Egress specifies the configuration of the sidecar for processing
// outbound traffic from the attached workload instance to other
// services in the mesh. If not specified, inherits the system
// detected defaults from the namespace-wide or the global default Sidecar.
repeated IstioEgressListener egress = 3;
// Configuration for the outbound traffic policy. If your
// application uses one or more external services that are not known
// apriori, setting the policy to `ALLOW_ANY` will cause the
// sidecars to route any unknown traffic originating from the
// application to its requested destination. If not specified,
// inherits the system detected defaults from the namespace-wide or
// the global default Sidecar.
OutboundTrafficPolicy outbound_traffic_policy = 4;
reserved "localhost";
reserved 5, 6;
}
// `IstioIngressListener` specifies the properties of an inbound
// traffic listener on the sidecar proxy attached to a workload instance.
message IstioIngressListener {
// The port associated with the listener.
Port port = 1 [(google.api.field_behavior) = REQUIRED];
// The IP to which the listener should be bound. Must be in the
// format `x.x.x.x`. Unix domain socket addresses are not allowed in
// the bind field for ingress listeners. If omitted, Istio will
// automatically configure the defaults based on imported services
// and the workload instances to which this configuration is applied
// to.
string bind = 2;
// The captureMode option dictates how traffic to the listener is
// expected to be captured (or not).
CaptureMode capture_mode = 3;
// The IP endpoint or Unix domain socket to which
// traffic should be forwarded to. This configuration can be used to
// redirect traffic arriving at the bind `IP:Port` on the sidecar to a `localhost:port`
// or Unix domain socket where the application workload instance is listening for
// connections. Arbitrary IPs are not supported. Format should be one of `127.0.0.1:PORT`, `0.0.0.0:PORT`
// (which will forward to the instance IP), or `unix:///path/to/socket`
string default_endpoint = 4 [(google.api.field_behavior) = REQUIRED];
reserved "localhost_client_tls";
reserved 5, 6;
}
// `IstioEgressListener` specifies the properties of an outbound traffic
// listener on the sidecar proxy attached to a workload instance.
message IstioEgressListener {
// The port associated with the listener. If using Unix domain socket,
// use 0 as the port number, with a valid protocol. The port if
// specified, will be used as the default destination port associated
// with the imported hosts. If the port is omitted, Istio will infer the
// listener ports based on the imported hosts. Note that when multiple
// egress listeners are specified, where one or more listeners have
// specific ports while others have no port, the hosts exposed on a
// listener port will be based on the listener with the most specific
// port.
Port port = 1;
// The IP or the Unix domain socket to which the listener should be bound
// to. Port MUST be specified if bind is not empty. Format: `x.x.x.x` or
// `unix:///path/to/uds` or `unix://@foobar` (Linux abstract namespace). If
// omitted, Istio will automatically configure the defaults based on imported
// services, the workload instances to which this configuration is applied to and
// the captureMode. If captureMode is `NONE`, bind will default to
// 127.0.0.1.
string bind = 2;
// When the bind address is an IP, the captureMode option dictates
// how traffic to the listener is expected to be captured (or not).
// captureMode must be DEFAULT or `NONE` for Unix domain socket binds.
CaptureMode capture_mode = 3;
// One or more service hosts exposed by the listener
// in `namespace/dnsName` format. Services in the specified namespace
// matching `dnsName` will be exposed.
// The corresponding service can be a service in the service registry
// (e.g., a Kubernetes or cloud foundry service) or a service specified
// using a `ServiceEntry` or `VirtualService` configuration. Any
// associated `DestinationRule` in the same namespace will also be used.
//
// The `dnsName` should be specified using FQDN format, optionally including
// a wildcard character in the left-most component (e.g., `prod/*.example.com`).
// Set the `dnsName` to `*` to select all services from the specified namespace
// (e.g., `prod/*`).
//
// The `namespace` can be set to `*`, `.`, or `~`, representing any, the current,
// or no namespace, respectively. For example, `*/foo.example.com` selects the
// service from any available namespace while `./foo.example.com` only selects
// the service from the namespace of the sidecar. If a host is set to `*/*`,
// Istio will configure the sidecar to be able to reach every service in the
// mesh that is exported to the sidecar's namespace. The value `~/*` can be used
// to completely trim the configuration for sidecars that simply receive traffic
// and respond, but make no outbound connections of their own.
//
// NOTE: Only services and configuration artifacts exported to the sidecar's
// namespace (e.g., `exportTo` value of `*`) can be referenced.
// Private configurations (e.g., `exportTo` set to `.`) will
// not be available. Refer to the `exportTo` setting in `VirtualService`,
// `DestinationRule`, and `ServiceEntry` configurations for details.
//
// **WARNING:** The list of egress hosts in a `Sidecar` must also include
// the Mixer control plane services if they are enabled. Envoy will not
// be able to reach them otherwise. For example, add host
// `istio-system/istio-telemetry.istio-system.svc.cluster.local` if telemetry
// is enabled, `istio-system/istio-policy.istio-system.svc.cluster.local` if
// policy is enabled, or add `istio-system/*` to allow all services in the
// `istio-system` namespace. This requirement is temporary and will be removed
// in a future Istio release.
repeated string hosts = 4 [(google.api.field_behavior) = REQUIRED];
reserved "localhost_server_tls";
reserved 5, 6;
}
// `WorkloadSelector` specifies the criteria used to determine if the
// `Gateway`, `Sidecar`, or `EnvoyFilter` or `ServiceEntry`
// configuration can be applied to a proxy. The matching criteria
// includes the metadata associated with a proxy, workload instance
// info such as labels attached to the pod/VM, or any other info that
// the proxy provides to Istio during the initial handshake. If
// multiple conditions are specified, all conditions need to match in
// order for the workload instance to be selected. Currently, only
// label based selection mechanism is supported.
message WorkloadSelector {
// One or more labels that indicate a specific set of pods/VMs
// on which the configuration should be applied. The scope of
// label search is restricted to the configuration namespace in which the
// the resource is present.
map<string, string> labels = 1 [(google.api.field_behavior) = REQUIRED];
// $hide_from_docs
// other forms of identification supplied by the proxy
// when connecting to Pilot, such as X509 fields, tenant IDs, JWT,
// etc. This has nothing to do with the request level authN etc.
}
// `OutboundTrafficPolicy` sets the default behavior of the sidecar for
// handling outbound traffic from the application.
// If your application uses one or more external
// services that are not known apriori, setting the policy to `ALLOW_ANY`
// will cause the sidecars to route any unknown traffic originating from
// the application to its requested destination. Users are strongly
// encouraged to use `ServiceEntry` configurations to explicitly declare any external
// dependencies, instead of using `ALLOW_ANY`, so that traffic to these
// services can be monitored.
message OutboundTrafficPolicy {
enum Mode {
// Outbound traffic will be restricted to services defined in the
// service registry as well as those defined through `ServiceEntry` configurations.
REGISTRY_ONLY = 0;
// Outbound traffic to unknown destinations will be allowed, in case
// there are no services or `ServiceEntry` configurations for the destination port.
ALLOW_ANY = 1;
}
Mode mode = 1;
// Specifies the details of the egress proxy to which unknown
// traffic should be forwarded to from the sidecar. Valid only if
// the mode is set to ALLOW_ANY. If not specified when the mode is
// ALLOW_ANY, the sidecar will send the unknown traffic directly to
// the IP requested by the application.
//
// ** NOTE 1**: The specified egress host must be imported in the
// egress section for the traffic forwarding to work.
//
// ** NOTE 2**: An Envoy based egress gateway is unlikely to be able
// to handle plain text TCP connections forwarded from the sidecar.
// Envoy's dynamic forward proxy can handle only HTTP and TLS
// connections.
// $hide_from_docs
istio.networking.v1alpha3.Destination egress_proxy = 2;
}
// `CaptureMode` describes how traffic to a listener is expected to be
// captured. Applicable only when the listener is bound to an IP.
enum CaptureMode {
// The default capture mode defined by the environment.
DEFAULT = 0;
// Capture traffic using IPtables redirection.
IPTABLES = 1;
// No traffic capture. When used in an egress listener, the application is
// expected to explicitly communicate with the listener port or Unix
// domain socket. When used in an ingress listener, care needs to be taken
// to ensure that the listener port is not in use by other processes on
// the host.
NONE = 2;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,325 @@
// Copyright 2020 Istio Authors
//
// Licensed 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.
syntax = "proto3";
import "google/api/field_behavior.proto";
// $schema: istio.networking.v1alpha3.WorkloadEntry
// $title: Workload Entry
// $description: Configuration affecting VMs onboarded into the mesh.
// $location: https://istio.io/docs/reference/config/networking/workload-entry.html
// $aliases: [/docs/reference/config/networking/v1alpha3/workload-entry]
// `WorkloadEntry` enables operators to describe the properties of a
// single non-Kubernetes workload such as a VM or a bare metal server
// as it is onboarded into the mesh. A `WorkloadEntry` must be
// accompanied by an Istio `ServiceEntry` that selects the workload
// through the appropriate labels and provides the service definition
// for a `MESH_INTERNAL` service (hostnames, port properties, etc.). A
// `ServiceEntry` object can select multiple workload entries as well
// as Kubernetes pods based on the label selector specified in the
// service entry.
//
// When a workload connects to `istiod`, the status field in the
// custom resource will be updated to indicate the health of the
// workload along with other details, similar to how Kubernetes
// updates the status of a pod.
//
// The following example declares a workload entry representing a VM
// for the `details.bookinfo.com` service. This VM has sidecar
// installed and bootstrapped using the `details-legacy` service
// account. The service is exposed on port 80 to applications in the
// mesh. The HTTP traffic to this service is wrapped in Istio mutual
// TLS and sent to sidecars on VMs on target port 8080, that in turn
// forward it to the application on localhost on the same port.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: WorkloadEntry
// metadata:
// name: details-svc
// spec:
// # use of the service account indicates that the workload has a
// # sidecar proxy bootstrapped with this service account. Pods with
// # sidecars will automatically communicate with the workload using
// # istio mutual TLS.
// serviceAccount: details-legacy
// address: 2.2.2.2
// labels:
// app: details-legacy
// instance-id: vm1
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: WorkloadEntry
// metadata:
// name: details-svc
// spec:
// # use of the service account indicates that the workload has a
// # sidecar proxy bootstrapped with this service account. Pods with
// # sidecars will automatically communicate with the workload using
// # istio mutual TLS.
// serviceAccount: details-legacy
// address: 2.2.2.2
// labels:
// app: details-legacy
// instance-id: vm1
// ```
// {{</tab>}}
// {{</tabset>}}
//
// and the associated service entry
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: details-svc
// spec:
// hosts:
// - details.bookinfo.com
// location: MESH_INTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// targetPort: 8080
// resolution: STATIC
// workloadSelector:
// labels:
// app: details-legacy
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: details-svc
// spec:
// hosts:
// - details.bookinfo.com
// location: MESH_INTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// targetPort: 8080
// resolution: STATIC
// workloadSelector:
// labels:
// app: details-legacy
// ```
// {{</tab>}}
// {{</tabset>}}
//
//
// The following example declares the same VM workload using
// its fully qualified DNS name. The service entry's resolution
// mode should be changed to DNS to indicate that the client-side
// sidecars should dynamically resolve the DNS name at runtime before
// forwarding the request.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: WorkloadEntry
// metadata:
// name: details-svc
// spec:
// # use of the service account indicates that the workload has a
// # sidecar proxy bootstrapped with this service account. Pods with
// # sidecars will automatically communicate with the workload using
// # istio mutual TLS.
// serviceAccount: details-legacy
// address: vm1.vpc01.corp.net
// labels:
// app: details-legacy
// instance-id: vm1
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: WorkloadEntry
// metadata:
// name: details-svc
// spec:
// # use of the service account indicates that the workload has a
// # sidecar proxy bootstrapped with this service account. Pods with
// # sidecars will automatically communicate with the workload using
// # istio mutual TLS.
// serviceAccount: details-legacy
// address: vm1.vpc01.corp.net
// labels:
// app: details-legacy
// instance-id: vm1
// ```
// {{</tab>}}
// {{</tabset>}}
//
// and the associated service entry
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: ServiceEntry
// metadata:
// name: details-svc
// spec:
// hosts:
// - details.bookinfo.com
// location: MESH_INTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// targetPort: 8080
// resolution: DNS
// workloadSelector:
// labels:
// app: details-legacy
// ```
// {{</tab>}}
//
// {{<tab name="v1beta1" category-value="v1beta1">}}
// ```yaml
// apiVersion: networking.istio.io/v1beta1
// kind: ServiceEntry
// metadata:
// name: details-svc
// spec:
// hosts:
// - details.bookinfo.com
// location: MESH_INTERNAL
// ports:
// - number: 80
// name: http
// protocol: HTTP
// targetPort: 8080
// resolution: DNS
// workloadSelector:
// labels:
// app: details-legacy
// ```
// {{</tab>}}
// {{</tabset>}}
//
package istio.networking.v1alpha3;
option go_package = "istio.io/api/networking/v1alpha3";
// WorkloadEntry enables specifying the properties of a single non-Kubernetes workload such a VM or a bare metal services that can be referred to by service entries.
//
// <!-- crd generation tags
// +cue-gen:WorkloadEntry:groupName:networking.istio.io
// +cue-gen:WorkloadEntry:version:v1alpha3
// +cue-gen:WorkloadEntry:storageVersion
// +cue-gen:WorkloadEntry:annotations:helm.sh/resource-policy=keep
// +cue-gen:WorkloadEntry:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
// +cue-gen:WorkloadEntry:subresource:status
// +cue-gen:WorkloadEntry:scope:Namespaced
// +cue-gen:WorkloadEntry:resource:categories=istio-io,networking-istio-io,shortNames=we,plural=workloadentries
// +cue-gen:WorkloadEntry:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
// representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
// Clients may not set this value. It is represented in RFC3339 form and is in UTC.
// Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
// +cue-gen:WorkloadEntry:printerColumn:name=Address,type=string,JSONPath=.spec.address,description="Address associated with the network endpoint."
// +cue-gen:WorkloadEntry:preserveUnknownFields:false
// -->
//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=networking.istio.io/v1alpha3
// +genclient
// +k8s:deepcopy-gen=true
// -->
message WorkloadEntry {
// Address associated with the network endpoint without the
// port. Domain names can be used if and only if the resolution is set
// to DNS, and must be fully-qualified without wildcards. Use the form
// unix:///absolute/path/to/socket for Unix domain socket endpoints.
string address = 1 [(google.api.field_behavior) = REQUIRED];
// Set of ports associated with the endpoint. If the port map is
// specified, it must be a map of servicePortName to this endpoint's
// port, such that traffic to the service port will be forwarded to
// the endpoint port that maps to the service's portName. If
// omitted, and the targetPort is specified as part of the service's
// port specification, traffic to the service port will be forwarded
// to one of the endpoints on the specified `targetPort`. If both
// the targetPort and endpoint's port map are not specified, traffic
// to a service port will be forwarded to one of the endpoints on
// the same port.
//
// **NOTE 1:** Do not use for `unix://` addresses.
//
// **NOTE 2:** endpoint port map takes precedence over targetPort.
map<string, uint32> ports = 2;
// One or more labels associated with the endpoint.
map<string, string> labels = 3;
// Network enables Istio to group endpoints resident in the same L3
// domain/network. All endpoints in the same network are assumed to be
// directly reachable from one another. When endpoints in different
// networks cannot reach each other directly, an Istio Gateway can be
// used to establish connectivity (usually using the
// `AUTO_PASSTHROUGH` mode in a Gateway Server). This is
// an advanced configuration used typically for spanning an Istio mesh
// over multiple clusters.
string network = 4;
// The locality associated with the endpoint. A locality corresponds
// to a failure domain (e.g., country/region/zone). Arbitrary failure
// domain hierarchies can be represented by separating each
// encapsulating failure domain by /. For example, the locality of an
// an endpoint in US, in US-East-1 region, within availability zone
// az-1, in data center rack r11 can be represented as
// us/us-east-1/az-1/r11. Istio will configure the sidecar to route to
// endpoints within the same locality as the sidecar. If none of the
// endpoints in the locality are available, endpoints parent locality
// (but within the same network ID) will be chosen. For example, if
// there are two endpoints in same network (networkID "n1"), say e1
// with locality us/us-east-1/az-1/r11 and e2 with locality
// us/us-east-1/az-2/r12, a sidecar from us/us-east-1/az-1/r11 locality
// will prefer e1 from the same locality over e2 from a different
// locality. Endpoint e2 could be the IP associated with a gateway
// (that bridges networks n1 and n2), or the IP associated with a
// standard service endpoint.
string locality = 5;
// The load balancing weight associated with the endpoint. Endpoints
// with higher weights will receive proportionally higher traffic.
uint32 weight = 6;
// The service account associated with the workload if a sidecar
// is present in the workload. The service account must be present
// in the same namespace as the configuration ( WorkloadEntry or a
// ServiceEntry)
string service_account = 7;
};

View File

@ -0,0 +1,206 @@
// Copyright 2020 Istio Authors
//
// Licensed 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.
syntax = "proto3";
import "google/api/field_behavior.proto";
import "networking/v1alpha3/workload_entry.proto";
// $schema: istio.networking.v1alpha3.WorkloadGroup
// $title: Workload Group
// $description: Describes a collection of workload instances.
// $location: https://istio.io/docs/reference/config/networking/workload-group.html
// $aliases: [/docs/reference/config/networking/v1alpha3/workload-group]
// `WorkloadGroup` describes a collection of workload instances.
// It provides a specification that the workload instances can use to bootstrap
// their proxies, including the metadata and identity. It is only intended to
// be used with non-k8s workloads like Virtual Machines, and is meant to mimic
// the existing sidecar injection and deployment specification model used for
// Kubernetes workloads to bootstrap Istio proxies.
//
// The following example declares a workload group representing a collection
// of workloads that will be registered under `reviews` in namespace
// `bookinfo`. The set of labels will be associated with each workload
// instance during the bootstrap process, and the ports 3550 and 8080
// will be associated with the workload group and use service account `default`.
// `app.kubernetes.io/version` is just an arbitrary example of a label.
//
// {{<tabset category-name="example">}}
// {{<tab name="v1alpha3" category-value="v1alpha3">}}
// ```yaml
// apiVersion: networking.istio.io/v1alpha3
// kind: WorkloadGroup
// metadata:
// name: reviews
// namespace: bookinfo
// spec:
// metadata:
// labels:
// app.kubernetes.io/name: reviews
// app.kubernetes.io/version: "1.3.4"
// template:
// ports:
// grpc: 3550
// http: 8080
// serviceAccount: default
// probe:
// initialDelaySeconds: 5
// timeoutSeconds: 3
// periodSeconds: 4
// successThreshold: 3
// failureThreshold: 3
// httpGet:
// path: /foo/bar
// host: 127.0.0.1
// port: 3100
// scheme: https
// httpHeaders:
// - name: Lit-Header
// value: Im-The-Best
// ```
// {{</tab>}}
// {{</tabset>}}
//
package istio.networking.v1alpha3;
option go_package = "istio.io/api/networking/v1alpha3";
// `WorkloadGroup` enables specifying the properties of a single workload for bootstrap and
// provides a template for `WorkloadEntry`, similar to how `Deployment` specifies properties
// of workloads via `Pod` templates. A `WorkloadGroup` can have more than one `WorkloadEntry`.
// `WorkloadGroup` has no relationship to resources which control service registry like `ServiceEntry`
// and as such doesn't configure host name for these workloads.
//
// <!-- crd generation tags
// +cue-gen:WorkloadGroup:groupName:networking.istio.io
// +cue-gen:WorkloadGroup:version:v1alpha3
// +cue-gen:WorkloadGroup:storageVersion
// +cue-gen:WorkloadGroup:subresource:status
// +cue-gen:WorkloadGroup:scope:Namespaced
// +cue-gen:WorkloadGroup:resource:categories=istio-io,networking-istio-io,shortNames=wg,plural=workloadgroups
// +cue-gen:WorkloadGroup:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
// representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
// Clients may not set this value. It is represented in RFC3339 form and is in UTC.
// Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
// +cue-gen:WorkloadGroup:preserveUnknownFields:false
// -->
//
// <!-- go code generation tags
// +kubetype-gen
// +kubetype-gen:groupVersion=networking.istio.io/v1alpha3
// +genclient
// +k8s:deepcopy-gen=true
// -->
message WorkloadGroup {
// Metadata that will be used for all corresponding `WorkloadEntries`.
// User labels for a workload group should be set here in `metadata` rather than in `template`.
ObjectMeta metadata = 1;
// Template to be used for the generation of `WorkloadEntry` resources that belong to this `WorkloadGroup`.
// Please note that `address` and `labels` fields should not be set in the template, and an empty `serviceAccount`
// should default to `default`. The workload identities (mTLS certificates) will be bootstrapped using the
// specified service account's token. Workload entries in this group will be in the same namespace as the
// workload group, and inherit the labels and annotations from the above `metadata` field.
WorkloadEntry template = 2 [(google.api.field_behavior) = REQUIRED];
// `ObjectMeta` describes metadata that will be attached to a `WorkloadEntry`.
// It is a subset of the supported Kubernetes metadata.
message ObjectMeta {
// Labels to attach
map<string, string> labels = 1;
// Annotations to attach
map<string, string> annotations = 2;
}
// `ReadinessProbe` describes the configuration the user must provide for healthchecking on their workload.
// This configuration mirrors K8S in both syntax and logic for the most part.
ReadinessProbe probe = 3;
}
message ReadinessProbe {
// Number of seconds after the container has started before readiness probes are initiated.
int32 initial_delay_seconds = 2;
// Number of seconds after which the probe times out.
// Defaults to 1 second. Minimum value is 1 second.
int32 timeout_seconds = 3;
// How often (in seconds) to perform the probe.
// Default to 10 seconds. Minimum value is 1 second.
int32 period_seconds = 4;
// Minimum consecutive successes for the probe to be considered successful after having failed.
// Defaults to 1 second.
int32 success_threshold = 5;
// Minimum consecutive failures for the probe to be considered failed after having succeeded.
// Defaults to 3 seconds.
int32 failure_threshold = 6;
// Users can only provide one configuration for healthchecks (tcp, http, exec),
// and this is expressed as a oneof. All of the other configuration values
// hold true for any of the healthcheck methods.
oneof health_check_method {
// `httpGet` is performed to a given endpoint
// and the status/able to connect determines health.
HTTPHealthCheckConfig http_get = 7;
// Health is determined by if the proxy is able to connect.
TCPHealthCheckConfig tcp_socket = 8;
// Health is determined by how the command that is executed exited.
ExecHealthCheckConfig exec = 9;
}
}
message HTTPHealthCheckConfig {
// Path to access on the HTTP server.
string path = 1;
// Port on which the endpoint lives.
uint32 port = 2;
// Host name to connect to, defaults to the pod IP. You probably want to set
// "Host" in httpHeaders instead.
string host = 3;
// HTTP or HTTPS, defaults to HTTP
string scheme = 4;
// Headers the proxy will pass on to make the request.
// Allows repeated headers.
repeated HTTPHeader http_headers = 5;
}
message HTTPHeader {
// The header field name
string name = 1;
// The header field value
string value = 2;
}
message TCPHealthCheckConfig {
// Host to connect to, defaults to localhost
string host = 1;
// Port of host
uint32 port = 2;
}
message ExecHealthCheckConfig {
// Command to run. Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
repeated string command = 1;
}