Skip to content

Commit 5516436

Browse files
committed
refactor
1 parent d047a88 commit 5516436

File tree

2 files changed

+66
-179
lines changed

2 files changed

+66
-179
lines changed

custom-domain/dstack-ingress/scripts/certman.py

Lines changed: 64 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -81,226 +81,135 @@ def install_plugin(self) -> bool:
8181

8282
print(f"Successfully installed {self.provider.CERTBOT_PACKAGE}")
8383

84-
# Add diagnostic information
84+
# Diagnostic information for troubleshooting
8585
try:
86-
print("=== Diagnostic Information ===")
87-
# Check which Python executable is being used
8886
import sys
89-
print(f"Python executable: {sys.executable}")
90-
print(f"Python version: {sys.version}")
91-
92-
# Check where the package was installed
9387
import pkg_resources
88+
print(f"Installed to Python: {sys.executable}")
89+
9490
try:
9591
dist = pkg_resources.get_distribution("certbot-dns-namecheap")
96-
print(f"Package location: {dist.location}")
97-
print(f"Package version: {dist.version}")
92+
print(f"Package version: {dist.version} at {dist.location}")
9893
except pkg_resources.DistributionNotFound:
99-
print("Package not found in current environment")
100-
101-
# Check sys.path
102-
print(f"Python path: {sys.path[:3]}...")
103-
print("=== End Diagnostic Information ===")
94+
print("Warning: Package not found in current environment")
10495
except Exception as diag_error:
10596
print(f"Diagnostic error: {diag_error}")
10697

107-
# For Docker environments, we need to check if the plugin is actually usable
108-
# Try a direct test of the plugin functionality
98+
# Verify plugin installation
10999
try:
110100
if self.provider.CERTBOT_PLUGIN == "dns-namecheap":
111101
import certbot_dns_namecheap.dns_namecheap
112102
print(f"Plugin {self.provider.CERTBOT_PLUGIN} successfully imported")
113103

114-
# Try to create a simple test to see if the plugin works
115-
print(f"Testing if plugin {self.provider.CERTBOT_PLUGIN} is available...")
104+
# Test if plugin is recognized by certbot
116105
test_cmd = ["certbot", "plugins"]
117106
test_result = subprocess.run(test_cmd, capture_output=True, text=True, timeout=10)
118107

119-
print(f"Certbot plugins command returned: {test_result.returncode}")
120-
if test_result.stdout:
121-
print(f"Available plugins:")
122-
print(test_result.stdout)
123-
124-
if test_result.stderr:
125-
print(f"Plugin test stderr: {test_result.stderr}")
126-
127108
if test_result.returncode == 0 and "dns-namecheap" in test_result.stdout:
128-
print(f"Plugin {self.provider.CERTBOT_PLUGIN} is available and working correctly")
109+
print(f"Plugin {self.provider.CERTBOT_PLUGIN} is available in certbot")
129110
return True
130111
else:
131-
print(f"Plugin {self.provider.CERTBOT_PLUGIN} may not be properly installed")
132-
if "dns-namecheap" not in test_result.stdout:
133-
print(f"Warning: dns-namecheap plugin not found in certbot plugins list")
134-
135-
# Try some additional fixes
136-
print("Attempting additional fixes...")
137-
138-
# Try to reload Python modules
139-
try:
140-
import importlib
141-
import certbot_dns_namecheap
142-
importlib.reload(certbot_dns_namecheap)
143-
print("Reloaded certbot_dns_namecheap module")
144-
except Exception as reload_error:
145-
print(f"Module reload failed: {reload_error}")
146-
147-
# Try installing with --force-reinstall
148-
try:
149-
print("Trying force reinstall...")
150-
import sys
151-
force_cmd = [sys.executable, "-m", "pip", "install", "--force-reinstall", self.provider.CERTBOT_PACKAGE]
152-
print(f"Force reinstall command: {' '.join(force_cmd)}")
153-
force_result = subprocess.run(force_cmd, capture_output=True, text=True)
154-
if force_result.returncode == 0:
155-
print("Force reinstall succeeded")
156-
else:
157-
print(f"Force reinstall failed: {force_result.stderr}")
158-
except Exception as force_error:
159-
print(f"Force reinstall error: {force_error}")
160-
161-
# Test plugins again after fixes
162-
print("Testing plugins again after fixes...")
163-
retest_cmd = ["certbot", "plugins"]
164-
retest_result = subprocess.run(retest_cmd, capture_output=True, text=True, timeout=10)
165-
if retest_result.returncode == 0 and "dns-namecheap" in retest_result.stdout:
166-
print(f"Plugin {self.provider.CERTBOT_PLUGIN} is now available after fixes!")
167-
return True
168-
169-
# In Docker environments, this might still work in practice
170-
print("Continuing anyway - plugin may work in actual certbot execution")
112+
print(f"Warning: dns-namecheap plugin not found in certbot plugins list")
113+
if test_result.stderr:
114+
print(f"Plugin test stderr: {test_result.stderr}")
115+
# Continue anyway - may work in Docker environments
171116
return True
172117

173118
except Exception as e:
174-
print(f"Plugin test warning: {e}")
175-
# Continue anyway - the plugin may still work
119+
print(f"Plugin verification warning: {e}")
176120
return True
177121

178122
return True
179123

124+
def _validate_provider_credentials(self) -> bool:
125+
"""Validate provider credentials by testing API access."""
126+
print(f"Validating {self.provider_type} API credentials...")
127+
128+
try:
129+
# For Namecheap, test API access
130+
if hasattr(self.provider, '_make_request'):
131+
test_result = self.provider._make_request("namecheap.users.getBalances")
132+
if test_result.get("success", False):
133+
print(f"✓ {self.provider_type} API credentials are valid")
134+
return True
135+
else:
136+
print(f"✗ {self.provider_type} API validation failed: {test_result.get('errors', ['Unknown error'])}")
137+
return False
138+
else:
139+
print(f"No API validation available for {self.provider_type}, skipping")
140+
return True
141+
except Exception as e:
142+
print(f"Error validating {self.provider_type} credentials: {e}")
143+
return False
144+
180145
def setup_credentials(self) -> bool:
181146
"""Setup credentials file for certbot using provider implementation."""
182-
print(f"Setting up credentials for {self.provider_type} provider")
183147
result = self.provider.setup_certbot_credentials()
184-
if result:
185-
print(f"Credentials setup successful for {self.provider_type}")
186-
else:
187-
print(f"Credentials setup failed for {self.provider_type}")
148+
if not result:
149+
print(f"Failed to setup credentials file for {self.provider_type}")
188150
return result
189151

190152
def _build_certbot_command(self, action: str, domain: str, email: str) -> List[str]:
191153
"""Build certbot command using provider configuration."""
192-
print(f"Building certbot command for action: {action}, domain: {domain}")
193-
194154
plugin = self.provider.CERTBOT_PLUGIN
195-
print(f"Using plugin: {plugin}")
196-
197155
if not plugin:
198156
raise ValueError(f"No certbot plugin configured for {self.provider_type}")
199157

200-
propagation_seconds = self.provider.CERTBOT_PROPAGATION_SECONDS
201-
print(f"Propagation seconds configured: {propagation_seconds}")
202-
203-
base_cmd = ["certbot", action]
158+
base_cmd = ["certbot", action, "-a", plugin, "--non-interactive", "-v"]
204159

205-
# Add DNS plugin configuration
206-
base_cmd.extend(
207-
[
208-
"-a", plugin,
209-
"--non-interactive",
210-
"-v", # Add verbose flag for detailed output
211-
]
212-
)
213-
print(f"Added plugin and non-interactive flags")
214-
215-
# Add credentials file if provider has one configured
160+
# Add credentials file if configured
216161
if self.provider.CERTBOT_CREDENTIALS_FILE:
217-
credentials_file = os.path.expanduser(
218-
self.provider.CERTBOT_CREDENTIALS_FILE
219-
)
220-
print(f"Credentials file path (expanded): {credentials_file}")
221-
162+
credentials_file = os.path.expanduser(self.provider.CERTBOT_CREDENTIALS_FILE)
222163
if os.path.exists(credentials_file):
223-
credentials_arg = f"--{plugin}-credentials={credentials_file}"
224-
base_cmd.extend([credentials_arg])
225-
print(f"Added credentials argument: {credentials_arg}")
164+
base_cmd.extend([f"--{plugin}-credentials={credentials_file}"])
226165
else:
227-
print(f"Warning: Credentials file does not exist: {credentials_file}")
228-
else:
229-
print(f"No credentials file configured for provider")
166+
raise ValueError(f"Credentials file does not exist: {credentials_file}")
230167

231168
if action == "certonly":
232-
base_cmd.extend(
233-
["--agree-tos", "--no-eff-email", "--email", email, "-d", domain]
234-
)
235-
print(f"Added certonly-specific arguments")
169+
base_cmd.extend(["--agree-tos", "--no-eff-email", "--email", email, "-d", domain])
236170

237-
# Print the final command with masked email
238-
masked_cmd = []
239-
for i, arg in enumerate(base_cmd):
240-
if i > 0 and base_cmd[i-1] == "--email":
241-
masked_cmd.append("<email>")
242-
else:
243-
masked_cmd.append(arg)
244-
print(f"Final certbot command: {' '.join(masked_cmd)}")
171+
# Log command with masked email for debugging
172+
masked_cmd = [arg if not (i > 0 and base_cmd[i-1] == "--email") else "<email>"
173+
for i, arg in enumerate(base_cmd)]
174+
print(f"Executing: {' '.join(masked_cmd)}")
245175

246176
return base_cmd
247177

248178
def obtain_certificate(self, domain: str, email: str) -> bool:
249179
"""Obtain a new certificate for the domain."""
250-
print(f"Starting certificate obtaining process for {domain} using {self.provider_type}")
180+
print(f"Obtaining certificate for {domain} using {self.provider_type}")
251181

252182
# Ensure plugin is installed
253-
print(f"Checking plugin installation...")
254183
if not self.install_plugin():
255184
print(f"Failed to install plugin for {self.provider_type}", file=sys.stderr)
256185
return False
257-
print(f"Plugin installation completed")
258186

259-
# Check if credentials are set up
260-
print(f"Checking credentials setup...")
187+
# Validate credentials before proceeding
188+
if not self._validate_provider_credentials():
189+
print(f"Failed to validate credentials for {self.provider_type}", file=sys.stderr)
190+
return False
191+
192+
# Setup credentials file
261193
if not self.setup_credentials():
262194
print(f"Failed to setup credentials for {self.provider_type}", file=sys.stderr)
263195
return False
264-
print(f"Credentials setup completed")
265196

266-
# Check certbot version for debugging
267-
try:
268-
version_cmd = ["certbot", "--version"]
269-
version_result = subprocess.run(version_cmd, capture_output=True, text=True, timeout=10)
270-
if version_result.returncode == 0:
271-
print(f"Certbot version: {version_result.stdout.strip()}")
272-
else:
273-
print(f"Could not determine certbot version")
274-
except Exception as e:
275-
print(f"Error checking certbot version: {e}")
276-
277197
cmd = self._build_certbot_command("certonly", domain, email)
278-
print(f"Executing certbot command...")
279198

280199
try:
281200
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
282201

283-
print(f"Certbot command completed with return code: {result.returncode}")
284-
285-
# Always print stdout if available
286-
if result.stdout.strip():
287-
print(f"=== Certbot stdout ===")
288-
print(result.stdout)
289-
print(f"=== End stdout ===")
290-
291-
# Always print stderr if available
292-
if result.stderr.strip():
293-
print(f"=== Certbot stderr ===", file=sys.stderr)
294-
print(result.stderr, file=sys.stderr)
295-
print(f"=== End stderr ===", file=sys.stderr)
296-
297-
if result.returncode != 0:
298-
print(f"Certificate obtaining failed with return code {result.returncode}")
202+
if result.returncode == 0:
203+
print(f"✓ Certificate obtained successfully for {domain}")
204+
return True
205+
else:
206+
print(f"✗ Certificate obtaining failed (exit code: {result.returncode})")
207+
if result.stderr.strip():
208+
print(f"Error details: {result.stderr.strip()}")
209+
if result.stdout.strip():
210+
print(f"Output: {result.stdout.strip()}")
299211
return False
300212

301-
print(f"Certificate obtained successfully for {domain}")
302-
return True
303-
304213
except subprocess.TimeoutExpired:
305214
print(f"Certbot command timed out after 300 seconds", file=sys.stderr)
306215
return False
@@ -316,12 +225,10 @@ def renew_certificate(self, domain: str) -> Tuple[bool, bool]:
316225
"""
317226
print(f"Renewing certificate using {self.provider_type}")
318227

319-
# Ensure plugin is installed for renewal too
320-
print(f"Checking plugin installation for renewal...")
228+
# Ensure plugin is installed
321229
if not self.install_plugin():
322-
print(f"Failed to install plugin for renewal for {self.provider_type}", file=sys.stderr)
230+
print(f"Failed to install plugin for renewal", file=sys.stderr)
323231
return False, False
324-
print(f"Plugin installation completed for renewal")
325232

326233
cmd = self._build_certbot_command("renew", domain, "")
327234

custom-domain/dstack-ingress/scripts/dns_providers/namecheap.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,41 +34,21 @@ def __init__(self):
3434

3535
def setup_certbot_credentials(self) -> bool:
3636
"""Setup credentials file for certbot."""
37-
print(f"Setting up Namecheap credentials file...")
38-
3937
try:
4038
cred_dir = os.path.expanduser("~/.namecheap")
41-
print(f"Creating credentials directory: {cred_dir}")
4239
os.makedirs(cred_dir, exist_ok=True)
4340

4441
cred_file = os.path.join(cred_dir, "namecheap.ini")
45-
print(f"Writing credentials file: {cred_file}")
46-
4742
with open(cred_file, "w") as f:
4843
f.write(f"# Namecheap API credentials used by Certbot\n")
4944
f.write(f"dns_namecheap_username={self.username}\n")
5045
f.write(f"dns_namecheap_api_key={self.api_key}\n")
5146

52-
print(f"Setting file permissions to 0o600")
5347
os.chmod(cred_file, 0o600)
54-
55-
print(f"Credentials file created successfully: {cred_file}")
56-
57-
# Verify file contents (without showing sensitive data)
58-
if os.path.exists(cred_file):
59-
with open(cred_file, "r") as f:
60-
lines = f.readlines()
61-
print(f"Credentials file has {len(lines)} lines")
62-
for i, line in enumerate(lines):
63-
if line.startswith('#'):
64-
print(f"Line {i+1}: {line.strip()}")
65-
elif '=' in line:
66-
key = line.split('=')[0]
67-
print(f"Line {i+1}: {key}=<value>")
68-
48+
print(f"Credentials file created: {cred_file}")
6949
return True
7050
except Exception as e:
71-
print(f"Error setting up certbot credentials: {e}")
51+
print(f"Error setting up credentials file: {e}")
7252
return False
7353

7454
def _make_request(self, command: str, **params) -> Dict:

0 commit comments

Comments
 (0)