GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/swissknife_ingest.cc Lines: 0 94 0.0 %
Date: 2019-02-03 02:48:13 Branches: 0 52 0.0 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System
3
 */
4
5
#include "swissknife_ingest.h"
6
7
#include <fcntl.h>
8
#include <unistd.h>
9
10
#include "catalog_virtual.h"
11
#include "logging.h"
12
#include "manifest.h"
13
#include "statistics.h"
14
#include "sync_mediator.h"
15
#include "sync_union.h"
16
#include "sync_union_tarball.h"
17
#include "util/pointer.h"
18
#include "util/posix.h"
19
20
/*
21
 * Many of the options possible to set in the ArgumentList are not actually used
22
 * by the ingest command since they are not part of its interface, hence those
23
 * unused options cannot be set by the shell script. Of course if there is the
24
 * necessitty those paramenters can be added and managed.
25
 * At the moment this approach worked fine and didn't add much complexity,
26
 * however if yet another command will need to use a similar approach it would
27
 * be good to consider creating different options handler for each command.
28
 */
29
int swissknife::Ingest::Main(const swissknife::ArgumentList &args) {
30
  SyncParameters params;
31
  params.dir_rdonly = MakeCanonicalPath(*args.find('c')->second);
32
  params.dir_temp = MakeCanonicalPath(*args.find('t')->second);
33
  params.base_hash = shash::MkFromHexPtr(shash::HexPtr(*args.find('b')->second),
34
                                         shash::kSuffixCatalog);
35
  params.stratum0 = *args.find('w')->second;
36
  params.manifest_path = *args.find('o')->second;
37
  params.spooler_definition = *args.find('r')->second;
38
39
  params.public_keys = *args.find('K')->second;
40
  params.repo_name = *args.find('N')->second;
41
42
  if (args.find('T') != args.end()) {
43
    params.tar_file = *args.find('T')->second;
44
  }
45
  if (args.find('B') != args.end()) {
46
    params.base_directory = *args.find('B')->second;
47
  }
48
  if (args.find('D') != args.end()) {
49
    params.to_delete = *args.find('D')->second;
50
  }
51
52
  if (args.find('O') != args.end()) {
53
    params.generate_legacy_bulk_chunks = true;
54
  }
55
  shash::Algorithms hash_algorithm = shash::kSha1;
56
  if (args.find('e') != args.end()) {
57
    hash_algorithm = shash::ParseHashAlgorithm(*args.find('e')->second);
58
    if (hash_algorithm == shash::kAny) {
59
      PrintError("unknown hash algorithm");
60
      return 1;
61
    }
62
  }
63
  if (args.find('Z') != args.end()) {
64
    params.compression_alg =
65
        zlib::ParseCompressionAlgorithm(*args.find('Z')->second);
66
  }
67
68
  bool create_catalog = args.find('C') != args.end();
69
70
  params.nested_kcatalog_limit = SyncParameters::kDefaultNestedKcatalogLimit;
71
  params.root_kcatalog_limit = SyncParameters::kDefaultRootKcatalogLimit;
72
  params.file_mbyte_limit = SyncParameters::kDefaultFileMbyteLimit;
73
74
  params.branched_catalog = false;  // could be true?
75
76
  if (args.find('P') != args.end()) {
77
    params.session_token_file = *args.find('P')->second;
78
  }
79
80
  if (args.find('H') != args.end()) {
81
    params.key_file = *args.find('H')->second;
82
  }
83
84
  perf::StatisticsTemplate publish_statistics("Publish", this->statistics());
85
86
  upload::SpoolerDefinition spooler_definition(
87
      params.spooler_definition, hash_algorithm, params.compression_alg,
88
      params.generate_legacy_bulk_chunks, params.use_file_chunking,
89
      params.min_file_chunk_size, params.avg_file_chunk_size,
90
      params.max_file_chunk_size, params.session_token_file, params.key_file);
91
  if (params.max_concurrent_write_jobs > 0) {
92
    spooler_definition.number_of_concurrent_uploads =
93
        params.max_concurrent_write_jobs;
94
  }
95
96
  upload::SpoolerDefinition spooler_definition_catalogs(
97
      spooler_definition.Dup2DefaultCompression());
98
99
  params.spooler = upload::Spooler::Construct(spooler_definition,
100
                                              &publish_statistics);
101
  if (NULL == params.spooler) return 3;
102
  UniquePtr<upload::Spooler> spooler_catalogs(
103
      upload::Spooler::Construct(spooler_definition_catalogs));
104
  if (!spooler_catalogs.IsValid()) return 3;
105
106
  const bool follow_redirects = (args.count('L') > 0);
107
  if (!InitDownloadManager(follow_redirects)) {
108
    return 3;
109
  }
110
111
  if (!InitVerifyingSignatureManager(params.public_keys,
112
                                     params.trusted_certs)) {
113
    return 3;
114
  }
115
116
  bool with_gateway =
117
      spooler_definition.driver_type == upload::SpoolerDefinition::Gateway;
118
119
  UniquePtr<manifest::Manifest> manifest;
120
  if (params.branched_catalog) {
121
    // Throw-away manifest
122
    manifest = new manifest::Manifest(shash::Any(), 0, "");
123
  } else {
124
    if (with_gateway) {
125
      manifest =
126
          FetchRemoteManifest(params.stratum0, params.repo_name, shash::Any());
127
    } else {
128
      manifest = FetchRemoteManifest(params.stratum0, params.repo_name,
129
                                     params.base_hash);
130
    }
131
  }
132
  if (!manifest) {
133
    return 3;
134
  }
135
136
  const std::string old_root_hash = manifest->catalog_hash().ToString(true);
137
138
  catalog::WritableCatalogManager catalog_manager(
139
      params.base_hash, params.stratum0, params.dir_temp, spooler_catalogs,
140
      download_manager(), params.enforce_limits, params.nested_kcatalog_limit,
141
      params.root_kcatalog_limit, params.file_mbyte_limit, statistics(),
142
      params.is_balanced, params.max_weight, params.min_weight);
143
  catalog_manager.Init();
144
145
  publish::SyncMediator mediator(&catalog_manager, &params, publish_statistics);
146
147
  publish::SyncUnion *sync;
148
149
  sync = new publish::SyncUnionTarball(&mediator, params.dir_rdonly,
150
                                       params.tar_file, params.base_directory,
151
                                       params.to_delete, create_catalog);
152
  if (!sync->Initialize()) {
153
    LogCvmfs(kLogCvmfs, kLogStderr,
154
             "Initialization of the synchronisation "
155
             "engine failed");
156
    return 4;
157
  }
158
159
  sync->Traverse();
160
161
  if (!params.authz_file.empty()) {
162
    LogCvmfs(kLogCvmfs, kLogDebug,
163
             "Adding contents of authz file %s to"
164
             " root catalog.",
165
             params.authz_file.c_str());
166
    int fd = open(params.authz_file.c_str(), O_RDONLY);
167
    if (fd == -1) {
168
      LogCvmfs(kLogCvmfs, kLogStderr,
169
               "Unable to open authz file (%s)"
170
               "from the publication process: %s",
171
               params.authz_file.c_str(), strerror(errno));
172
      return 7;
173
    }
174
175
    std::string new_authz;
176
    const bool read_successful = SafeReadToString(fd, &new_authz);
177
    close(fd);
178
179
    if (!read_successful) {
180
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to read authz file (%s): %s",
181
               params.authz_file.c_str(), strerror(errno));
182
      return 8;
183
    }
184
185
    catalog_manager.SetVOMSAuthz(new_authz);
186
  }
187
188
  if (!mediator.Commit(manifest.weak_ref())) {
189
    PrintError("something went wrong during sync");
190
    return 5;
191
  }
192
193
  // finalize the spooler
194
  LogCvmfs(kLogCvmfs, kLogStdout, "Wait for all uploads to finish");
195
  params.spooler->WaitForUpload();
196
  spooler_catalogs->WaitForUpload();
197
  params.spooler->FinalizeSession(false);
198
199
  LogCvmfs(kLogCvmfs, kLogStdout, "Exporting repository manifest");
200
201
  // We call FinalizeSession(true) this time, to also trigger the commit
202
  // operation on the gateway machine (if the upstream is of type "gw").
203
204
  // Get the path of the new root catalog
205
  const std::string new_root_hash = manifest->catalog_hash().ToString(true);
206
207
  spooler_catalogs->FinalizeSession(true, old_root_hash, new_root_hash,
208
                                    params.repo_tag);
209
  delete params.spooler;
210
211
  if (!manifest->Export(params.manifest_path)) {
212
    PrintError("Failed to create new repository");
213
    return 6;
214
  }
215
216
  return 0;
217
}