1
#pragma once
2

            
3
#include "envoy/api/api.h"
4
#include "envoy/config/core/v3/config_source.pb.h"
5
#include "envoy/config/subscription.h"
6
#include "envoy/config/subscription_factory.h"
7
#include "envoy/event/dispatcher.h"
8
#include "envoy/filesystem/filesystem.h"
9
#include "envoy/protobuf/message_validator.h"
10

            
11
#include "source/common/common/logger.h"
12
#include "source/common/config/watched_directory.h"
13

            
14
namespace Envoy {
15
namespace Config {
16

            
17
envoy::config::core::v3::PathConfigSource makePathConfigSource(const std::string& path);
18

            
19
/**
20
 * Filesystem inotify implementation of the API Subscription interface. This allows the API to be
21
 * consumed on filesystem changes to files containing the JSON canonical representation of
22
 * lists of xDS resources.
23
 */
24
class FilesystemSubscriptionImpl : public Config::Subscription,
25
                                   protected Logger::Loggable<Logger::Id::config> {
26
public:
27
  FilesystemSubscriptionImpl(Event::Dispatcher& dispatcher,
28
                             const envoy::config::core::v3::PathConfigSource& path_config_source,
29
                             SubscriptionCallbacks& callbacks,
30
                             OpaqueResourceDecoderSharedPtr resource_decoder,
31
                             SubscriptionStats stats,
32
                             ProtobufMessage::ValidationVisitor& validation_visitor, Api::Api& api);
33

            
34
  // Config::Subscription
35
  // We report all discovered resources in the watched file, so the resource names arguments are
36
  // unused, and updateResourceInterest is a no-op (other than updating a stat).
37
  void start(const absl::flat_hash_set<std::string>&) override;
38
  void updateResourceInterest(const absl::flat_hash_set<std::string>&) override;
39
  void requestOnDemandUpdate(const absl::flat_hash_set<std::string>&) override {
40
    ENVOY_BUG(false, "unexpected request for on demand update");
41
  }
42

            
43
protected:
44
  virtual std::string refreshInternal(ProtobufTypes::MessagePtr* config_update);
45
  void refresh();
46
  void configRejected(const EnvoyException& e, const std::string& message);
47

            
48
  bool started_{};
49
  const std::string path_;
50
  std::unique_ptr<Filesystem::Watcher> file_watcher_;
51
  WatchedDirectoryPtr directory_watcher_;
52
  SubscriptionCallbacks& callbacks_;
53
  OpaqueResourceDecoderSharedPtr resource_decoder_;
54
  SubscriptionStats stats_;
55
  Api::Api& api_;
56
  ProtobufMessage::ValidationVisitor& validation_visitor_;
57
};
58

            
59
// Currently a FilesystemSubscriptionImpl subclass, but this will need to change when we support
60
// non-inline collection resources.
61
class FilesystemCollectionSubscriptionImpl : public FilesystemSubscriptionImpl {
62
public:
63
  FilesystemCollectionSubscriptionImpl(
64
      Event::Dispatcher& dispatcher,
65
      const envoy::config::core::v3::PathConfigSource& path_config_source,
66
      SubscriptionCallbacks& callbacks, OpaqueResourceDecoderSharedPtr resource_decoder,
67
      SubscriptionStats stats, ProtobufMessage::ValidationVisitor& validation_visitor,
68
      Api::Api& api);
69

            
70
  std::string refreshInternal(ProtobufTypes::MessagePtr* config_update) override;
71
};
72

            
73
class FilesystemSubscriptionFactory : public ConfigSubscriptionFactory {
74
public:
75
480
  std::string name() const override { return "envoy.config_subscription.filesystem"; }
76

            
77
10191
  SubscriptionPtr create(SubscriptionData& data) override {
78
10191
    if (data.config_.config_source_specifier_case() ==
79
10191
        envoy::config::core::v3::ConfigSource::ConfigSourceSpecifierCase::kPath) {
80
1
      return std::make_unique<Config::FilesystemSubscriptionImpl>(
81
1
          data.dispatcher_, makePathConfigSource(data.config_.path()), data.callbacks_,
82
1
          data.resource_decoder_, data.stats_, data.validation_visitor_, data.api_);
83
10191
    } else {
84
10190
      ASSERT(data.config_.config_source_specifier_case() ==
85
10190
             envoy::config::core::v3::ConfigSource::ConfigSourceSpecifierCase::kPathConfigSource);
86
10190
      return std::make_unique<Config::FilesystemSubscriptionImpl>(
87
10190
          data.dispatcher_, data.config_.path_config_source(), data.callbacks_,
88
10190
          data.resource_decoder_, data.stats_, data.validation_visitor_, data.api_);
89
10190
    }
90
10191
  }
91
};
92

            
93
class FilesystemCollectionSubscriptionFactory : public ConfigSubscriptionFactory {
94
public:
95
480
  std::string name() const override { return "envoy.config_subscription.filesystem_collection"; }
96

            
97
2
  SubscriptionPtr create(SubscriptionData& data) override {
98
2
    return std::make_unique<Config::FilesystemCollectionSubscriptionImpl>(
99
2
        data.dispatcher_, makePathConfigSource(data.config_.path()), data.callbacks_,
100
2
        data.resource_decoder_, data.stats_, data.validation_visitor_, data.api_);
101
2
  }
102
};
103

            
104
} // namespace Config
105
} // namespace Envoy