Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SMB outbound gateway doesn't seem to support the GET command #9211

Closed
smitsjelle opened this issue Jun 5, 2024 · 4 comments
Closed

SMB outbound gateway doesn't seem to support the GET command #9211

smitsjelle opened this issue Jun 5, 2024 · 4 comments

Comments

@smitsjelle
Copy link

Spring integration version used: 6.2.1 (also tested on 6.2.5)

When configuring a SMB outbound gateway through XML configuration with a 'get' command, and point the 'expression' field to the name of the file I with to retrieve, I receive an IOException: [path] is not a directory. Cannot list resources

Upon some further investigation, it appears that AbstractRemoteFileOutboundGateway#get, that is invoked for get commands will execute a list action against the (Smb)Session. The list action is supposed to return a single file. If so, it is copied to the local directory, otherwise an error is thrown. In contrast with the SftpSession#list, the SmbSession#list will always throw an example if a list is attempted on a non-directory SMB file.

It seems that the SmbSession should also have logic in place that will list the directory instead, and filter files based on the path provided, just like the SftpSession has? When using SFTP instead of SMB, a similar setup as presented below works.

To Reproduce
Configure a SMB share that hosts a simple 'smbtest.txt' file in the 'test' folder.

Run the XML below (with the proper directory) and see that.

<int:inbound-channel-adapter channel="trigger" expression="'trigger'">
	<int:poller fixed-delay="10" time-unit="SECONDS"/>
</int:inbound-channel-adapter>

<int:channel id="trigger"/>

<smb:outbound-gateway session-factory="smbSessionFactory" 
	request-channel="trigger" 
	reply-channel="nullChannel"
	remote-directory="/" 
	auto-create-directory="true"
	command="get" 
	expression="'smbtest.txt'"
	local-directory="tmp/" 
	auto-create-local-directory="true"/>
	
<bean id="smbSessionFactory" class="org.springframework.integration.smb.session.SmbSessionFactory">
	<property name="host" value="localhost"/>
	<property name="domain" value=""/>
	<property name="username" value="username"/>
	<property name="password" value="password"/>
	<property name="shareAndDir" value="test"/>
</bean>

Expected behavior
The file is created in the auto-created 'tmp' local directory.

@smitsjelle smitsjelle added status: waiting-for-triage The issue need to be evaluated and its future decided type: bug labels Jun 5, 2024
@artembilan artembilan added this to the 6.4.0-M1 milestone Jun 5, 2024
@artembilan artembilan added in: smb for: backport-to-6.2.x for: backport-to-6.3.x and removed status: waiting-for-triage The issue need to be evaluated and its future decided labels Jun 5, 2024
spring-builds pushed a commit that referenced this issue Jun 5, 2024
Fixes: #9211

The `AbstractRemoteFileOutboundGateway.get()` uses `Session.list()` for the provided remote file name.
The `SmbSession` does not support listing for a single file.

* Add logic into `SmbSession.list()` similar to `SftpSession.list()` to list a single remote file
on the provided path

(cherry picked from commit 91de12c)
spring-builds pushed a commit that referenced this issue Jun 5, 2024
Fixes: #9211

The `AbstractRemoteFileOutboundGateway.get()` uses `Session.list()` for the provided remote file name.
The `SmbSession` does not support listing for a single file.

* Add logic into `SmbSession.list()` similar to `SftpSession.list()` to list a single remote file
on the provided path

(cherry picked from commit 91de12c)
@artembilan
Copy link
Member

We just didn't have a respective test for plain GET. The one with .options(AbstractRemoteFileOutboundGateway.Option.STREAM) goes different path.
Fixed and will be released June 18.

Thank you for the report!

@smitsjelle
Copy link
Author

Hi, thank you for the quick reply and fix.

I have applied the fix and the problem using the SMB outbound gateway has indeed been resolved, but I now run into the issue that the behavior of the inbound channel adapter is also changed.

Previously, the setup described in the sample config below worked perfectly, giving me the files in my somedir/anotherdir directory. With the applied changes this 'list' operation is considered to be a get single file operation, and will fail with IOException: [somedir/anotherdir] is not a file. As a workaround, it seems that it is possible to provide 'remote-directory' as somedir\anotherdir, as that bypasses line 137 that checks for the occurence of the /, and the SMB calls seem to become normalized (as I am now effectively calling the path (...)/test/somedir\anotherdir/).

Is this intended behavior, where the remote directory may not contain multiple directories, and 'share and dir' of the SessionFactory must point to the parent of the desired directory? That seems to be in contrast with e.g. SFTP or file inbound gateways, where the 'remote directory' field can contain multiple directories.

Sample config:

<smb:inbound-channel-adapter 
    session-factory="smbSessionFactory" 
    local-directory="/tmp/smb"
    auto-create-local-directory="true"
    channel="smbInbound" 
    remote-directory="somedir/anotherdir"> <!-- Used to work pre-6.2.6, now needs to be 'somedir\anotherdir' to achieve the same -->
        <si:poller fixed-rate="10" time-unit="SECONDS"/>
</smb:inbound-channel-adapter>

<si:channel id="smbInbound"/>
(...)
<bean id="smbSessionFactory" class="org.springframework.integration.smb.session.SmbSessionFactory">
	<property name="host" value="localhost"/>
	<property name="domain" value=""/>
	<property name="username" value="username"/>
	<property name="password" value="password"/>
	<property name="shareAndDir" value="test"/>
</bean>

@artembilan
Copy link
Member

@smitsjelle ,

Thank you for feedback.
Please, raise a new issue.
Apparently this might even not work for SFTP as well.
Looks like an algorithm for LIST command was designed after FTP protocol.
We might need to come with something else for other protocols or revise whatever we do in the SmbSession.list() (and maybe SftpSession.list())

@artembilan
Copy link
Member

Taking that back.
Looks like it works for SFTP:

		IntegrationFlow flow = IntegrationFlow
				.from(Sftp.inboundAdapter(sessionFactory())
								.preserveTimestamp(true)
								.remoteDirectory("/sftpSource/subSftpSource")
								.regexFilter(".*\\.txt$")
								.localFilenameExpression("#this.toUpperCase() + '.a'")
								.localDirectory(getTargetLocalDirectory())
								.remoteComparator(Comparator.comparing(SftpClient.DirEntry::getFilename)),
						e -> e.id("sftpInboundAdapter").poller(Pollers.fixedDelay(100)))
				.channel(out)
				.get();

And my test fails as expected:

Expected :" SFTPSOURCE1.TXT.a"
Actual   :"SUBSFTPSOURCE1.TXT.a"

Anyway we need a new issue for new milestone(s).
Thanks

EddieChoCho pushed a commit to EddieChoCho/spring-integration that referenced this issue Jun 26, 2024
Fixes: spring-projects#9211

The `AbstractRemoteFileOutboundGateway.get()` uses `Session.list()` for the provided remote file name.
The `SmbSession` does not support listing for a single file.

* Add logic into `SmbSession.list()` similar to `SftpSession.list()` to list a single remote file
on the provided path

**Auto-cherry-pick to `6.3.x` & `6.2.x`**
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants